Update files
This commit is contained in:
parent
834982ef6c
commit
19b40b9160
|
|
@ -94,6 +94,67 @@ async function ensureBucket() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Нормализовать имя файла для MinIO (только ASCII, транслитерация кириллицы)
|
||||||
|
* @param {string} filename - Оригинальное имя файла
|
||||||
|
* @returns {string} - Безопасное имя файла
|
||||||
|
*/
|
||||||
|
function normalizeFilename(filename) {
|
||||||
|
if (!filename) return 'file';
|
||||||
|
|
||||||
|
// Извлечь расширение
|
||||||
|
const ext = filename.split('.').pop() || '';
|
||||||
|
const nameWithoutExt = filename.substring(0, filename.lastIndexOf('.')) || filename;
|
||||||
|
|
||||||
|
// Простая транслитерация кириллицы
|
||||||
|
const translitMap = {
|
||||||
|
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
|
||||||
|
'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
|
||||||
|
'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
|
||||||
|
'ф': 'f', 'х': 'h', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch',
|
||||||
|
'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
|
||||||
|
'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
|
||||||
|
'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M',
|
||||||
|
'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
|
||||||
|
'Ф': 'F', 'Х': 'H', 'Ц': 'Ts', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sch',
|
||||||
|
'Ъ': '', 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Транслитерировать имя
|
||||||
|
let normalized = nameWithoutExt
|
||||||
|
.split('')
|
||||||
|
.map(char => translitMap[char] || char)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
// Убрать все не-ASCII символы (оставить только буквы, цифры, дефис, подчеркивание)
|
||||||
|
normalized = normalized.replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||||
|
|
||||||
|
// Если имя пустое после нормализации, использовать 'file'
|
||||||
|
if (!normalized || normalized.trim() === '') {
|
||||||
|
normalized = 'file';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вернуть с расширением (расширение тоже нормализуем)
|
||||||
|
const safeExt = ext.replace(/[^a-zA-Z0-9]/g, '') || 'bin';
|
||||||
|
return safeExt ? `${normalized}.${safeExt}` : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Извлечь расширение файла безопасным способом
|
||||||
|
* @param {string} filename - Имя файла
|
||||||
|
* @returns {string} - Расширение файла
|
||||||
|
*/
|
||||||
|
function getFileExtension(filename) {
|
||||||
|
if (!filename) return 'bin';
|
||||||
|
|
||||||
|
const parts = filename.split('.');
|
||||||
|
if (parts.length < 2) return 'bin';
|
||||||
|
|
||||||
|
const ext = parts.pop().toLowerCase();
|
||||||
|
// Оставить только безопасные символы в расширении
|
||||||
|
return ext.replace(/[^a-z0-9]/g, '') || 'bin';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Загрузить файл в MinIO через S3 SDK
|
* Загрузить файл в MinIO через S3 SDK
|
||||||
* @param {Buffer} buffer - Буфер файла
|
* @param {Buffer} buffer - Буфер файла
|
||||||
|
|
@ -108,10 +169,13 @@ async function uploadFile(buffer, filename, contentType, folder = 'posts') {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Генерировать уникальное имя файла
|
// Нормализовать имя файла для MinIO (только ASCII)
|
||||||
|
const safeFilename = normalizeFilename(filename);
|
||||||
|
const ext = getFileExtension(filename);
|
||||||
|
|
||||||
|
// Генерировать уникальное имя файла (используем только timestamp и random, без оригинального имени)
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
const random = Math.round(Math.random() * 1E9);
|
const random = Math.round(Math.random() * 1E9);
|
||||||
const ext = filename.split('.').pop();
|
|
||||||
const objectName = `${folder}/${timestamp}-${random}.${ext}`;
|
const objectName = `${folder}/${timestamp}-${random}.${ext}`;
|
||||||
|
|
||||||
// Загрузить файл через S3 SDK
|
// Загрузить файл через S3 SDK
|
||||||
|
|
@ -119,12 +183,13 @@ async function uploadFile(buffer, filename, contentType, folder = 'posts') {
|
||||||
client: s3Client,
|
client: s3Client,
|
||||||
params: {
|
params: {
|
||||||
Bucket: config.minio.bucket,
|
Bucket: config.minio.bucket,
|
||||||
Key: objectName,
|
Key: objectName, // Используем безопасное имя для Key
|
||||||
Body: buffer,
|
Body: buffer,
|
||||||
ContentType: contentType,
|
ContentType: contentType,
|
||||||
CacheControl: 'public, max-age=31536000', // 1 год
|
CacheControl: 'public, max-age=31536000', // 1 год
|
||||||
Metadata: {
|
Metadata: {
|
||||||
originalname: filename,
|
// Сохраняем оригинальное имя в метаданных (URL-encoded для безопасности)
|
||||||
|
originalname: encodeURIComponent(filename),
|
||||||
uploadedAt: new Date().toISOString()
|
uploadedAt: new Date().toISOString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,13 +202,17 @@ async function uploadFile(buffer, filename, contentType, folder = 'posts') {
|
||||||
|
|
||||||
log('info', 'Файл загружен в MinIO через S3', {
|
log('info', 'Файл загружен в MinIO через S3', {
|
||||||
objectName,
|
objectName,
|
||||||
|
originalName: filename,
|
||||||
size: buffer.length,
|
size: buffer.length,
|
||||||
url: fileUrl
|
url: fileUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
return fileUrl;
|
return fileUrl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log('error', 'Ошибка загрузки файла в MinIO', { error: error.message });
|
log('error', 'Ошибка загрузки файла в MinIO', {
|
||||||
|
error: error.message,
|
||||||
|
filename: filename
|
||||||
|
});
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +255,7 @@ async function deleteFile(fileUrl) {
|
||||||
* @returns {Promise<number>} - Количество удаленных файлов
|
* @returns {Promise<number>} - Количество удаленных файлов
|
||||||
*/
|
*/
|
||||||
async function deleteFiles(fileUrls) {
|
async function deleteFiles(fileUrls) {
|
||||||
if (!minioClient || !fileUrls || !fileUrls.length) {
|
if (!s3Client || !fileUrls || !fileUrls.length) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue