- Added role field to Beneficiary type - Display role (Custodian/Guardian/Caretaker) in small gray text under name - Role comes from user_access table via API 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
130 lines
3.5 KiB
JavaScript
130 lines
3.5 KiB
JavaScript
/**
|
|
* MinIO Storage Service
|
|
* S3-compatible object storage for media files
|
|
*
|
|
* MinIO Console: https://minio-console.eluxnetworks.net
|
|
* S3 Endpoint: https://minio.eluxnetworks.net
|
|
*/
|
|
|
|
const { S3Client, PutObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
|
const crypto = require('crypto');
|
|
|
|
// MinIO Configuration
|
|
const MINIO_ENDPOINT = process.env.MINIO_ENDPOINT || 'https://minio.eluxnetworks.net';
|
|
const MINIO_ACCESS_KEY = process.env.MINIO_ACCESS_KEY;
|
|
const MINIO_SECRET_KEY = process.env.MINIO_SECRET_KEY;
|
|
const MINIO_BUCKET = process.env.MINIO_BUCKET || 'wellnuo';
|
|
|
|
// Public URL for accessing files
|
|
const PUBLIC_URL = process.env.MINIO_PUBLIC_URL || MINIO_ENDPOINT;
|
|
|
|
// Create S3 client for MinIO
|
|
const s3Client = new S3Client({
|
|
endpoint: MINIO_ENDPOINT,
|
|
region: 'us-east-1', // MinIO ignores this but requires it
|
|
credentials: {
|
|
accessKeyId: MINIO_ACCESS_KEY,
|
|
secretAccessKey: MINIO_SECRET_KEY,
|
|
},
|
|
forcePathStyle: true, // Required for MinIO
|
|
});
|
|
|
|
/**
|
|
* Upload a base64 image to MinIO
|
|
* @param {string} base64Data - Base64 data URI (data:image/png;base64,...)
|
|
* @param {string} folder - Folder path (e.g., 'avatars/beneficiaries')
|
|
* @param {string} [filename] - Optional filename, generated if not provided
|
|
* @returns {Promise<{url: string, key: string}>}
|
|
*/
|
|
async function uploadBase64Image(base64Data, folder, filename = null) {
|
|
if (!MINIO_ACCESS_KEY || !MINIO_SECRET_KEY) {
|
|
throw new Error('MinIO credentials not configured');
|
|
}
|
|
|
|
// Parse base64 data URI
|
|
const matches = base64Data.match(/^data:image\/(\w+);base64,(.+)$/);
|
|
if (!matches) {
|
|
throw new Error('Invalid base64 image format');
|
|
}
|
|
|
|
const [, extension, base64Content] = matches;
|
|
const buffer = Buffer.from(base64Content, 'base64');
|
|
|
|
// Generate filename if not provided
|
|
const finalFilename = filename || `${crypto.randomUUID()}.${extension}`;
|
|
const key = `${folder}/${finalFilename}`;
|
|
|
|
// Determine content type
|
|
const contentType = `image/${extension === 'jpg' ? 'jpeg' : extension}`;
|
|
|
|
console.log(`[STORAGE] Uploading ${key} (${buffer.length} bytes)`);
|
|
|
|
// Upload to MinIO
|
|
const command = new PutObjectCommand({
|
|
Bucket: MINIO_BUCKET,
|
|
Key: key,
|
|
Body: buffer,
|
|
ContentType: contentType,
|
|
ACL: 'public-read', // Make file publicly accessible
|
|
});
|
|
|
|
await s3Client.send(command);
|
|
|
|
// Return public URL
|
|
const url = `${PUBLIC_URL}/${MINIO_BUCKET}/${key}`;
|
|
|
|
console.log(`[STORAGE] Uploaded successfully: ${url}`);
|
|
|
|
return { url, key };
|
|
}
|
|
|
|
/**
|
|
* Delete a file from MinIO
|
|
* @param {string} key - Object key (path in bucket)
|
|
*/
|
|
async function deleteFile(key) {
|
|
if (!MINIO_ACCESS_KEY || !MINIO_SECRET_KEY) {
|
|
throw new Error('MinIO credentials not configured');
|
|
}
|
|
|
|
console.log(`[STORAGE] Deleting ${key}`);
|
|
|
|
const command = new DeleteObjectCommand({
|
|
Bucket: MINIO_BUCKET,
|
|
Key: key,
|
|
});
|
|
|
|
await s3Client.send(command);
|
|
|
|
console.log(`[STORAGE] Deleted successfully: ${key}`);
|
|
}
|
|
|
|
/**
|
|
* Extract key from MinIO URL
|
|
* @param {string} url - Full MinIO URL
|
|
* @returns {string|null} - Object key or null
|
|
*/
|
|
function extractKeyFromUrl(url) {
|
|
if (!url) return null;
|
|
|
|
// URL format: https://minio.eluxnetworks.net/wellnuo/avatars/xxx.png
|
|
const match = url.match(/\/wellnuo\/(.+)$/);
|
|
return match ? match[1] : null;
|
|
}
|
|
|
|
/**
|
|
* Check if storage is configured
|
|
*/
|
|
function isConfigured() {
|
|
return !!(MINIO_ACCESS_KEY && MINIO_SECRET_KEY);
|
|
}
|
|
|
|
module.exports = {
|
|
uploadBase64Image,
|
|
deleteFile,
|
|
extractKeyFromUrl,
|
|
isConfigured,
|
|
MINIO_BUCKET,
|
|
PUBLIC_URL,
|
|
};
|