Created a centralized logger utility (src/utils/logger.js) that provides: - Structured logging with context labels - Log levels (ERROR, WARN, INFO, DEBUG) - Environment-based log level control via LOG_LEVEL env variable - Consistent timestamp and JSON data formatting Removed console.log/error/warn statements from: - All service files (mqtt, notifications, legacyAPI, email, storage, subscription-sync) - All route handlers (auth, beneficiaries, deployments, webhook, admin, etc) - Controllers (dashboard, auth, alarm) - Database connection handler - Main server file (index.js) Preserved: - Critical startup validation error for JWT_SECRET in index.js Benefits: - Production-ready logging that can be easily integrated with log aggregation services - Reduced noise in production logs - Easier debugging with structured context and data - Configurable log levels per environment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
126 lines
3.3 KiB
JavaScript
126 lines
3.3 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}`;
|
|
|
|
|
|
// 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}`;
|
|
|
|
|
|
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');
|
|
}
|
|
|
|
|
|
const command = new DeleteObjectCommand({
|
|
Bucket: MINIO_BUCKET,
|
|
Key: key,
|
|
});
|
|
|
|
await s3Client.send(command);
|
|
|
|
}
|
|
|
|
/**
|
|
* 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,
|
|
};
|