Skip to content

Commit d82506d

Browse files
author
Xziy
committed
add support restore images from backup
1 parent a4a1386 commit d82506d

File tree

5 files changed

+147
-49
lines changed

5 files changed

+147
-49
lines changed

libs/BackupHandler.js

+37-9
Original file line numberDiff line numberDiff line change
@@ -75,32 +75,32 @@ class BackupHandler {
7575
// Import data and images from a tar file
7676
async importFromTar(filePath) {
7777
try {
78-
// Получаем текущую директорию
78+
// Get the current directory
7979
const currentDir = process.cwd();
80-
// Создаем директорию для распаковки
80+
// Create a directory for unpacking
8181
const timestamp = Date.now();
8282
this.workDir = path.join(currentDir, `.tmp/backup-${timestamp}`);
83-
// Создаем папку, если она не существует
83+
// Create a folder if it does not exist
8484
await fs_1.fsw.mkdir(this.workDir);
8585
console.log(`Extracting tar file to: ${this.workDir}`);
86-
// Распаковываем архив в указанную директорию
86+
// Unpack the archive into the specified directory
8787
await this.tar.x({
8888
file: filePath,
8989
cwd: this.workDir,
9090
});
91-
// Читаем данные JSON
91+
// Reading JSON data
9292
const jsonFilePath = path.join(this.workDir, 'data.json');
9393
const jsonData = await fs_1.fsw.readFile(jsonFilePath);
9494
const importedData = JSON.parse(jsonData);
9595
this.groups = importedData.groups;
9696
this.dishes = importedData.dishes;
97-
// Проверяем и загружаем изображения
97+
// Checking and uploading images
9898
for (const dish of this.dishes) {
9999
if (dish.images && Array.isArray(dish.images)) {
100100
let count = 1;
101101
for (const image of dish.images) {
102102
const ext = path.extname(image.originalFilePath) || '.webp';
103-
const imagePath = path.join(this.workDir, `${dish.id}_${count}${ext}`);
103+
const imagePath = path.join(this.workDir, `${dish.id}__${count}${ext}`);
104104
this.checkAndLoadImage(imagePath);
105105
count++;
106106
}
@@ -129,16 +129,44 @@ class BackupHandler {
129129
}
130130
// Check file existence and load image
131131
async checkAndLoadImage(imagePath) {
132+
// Извлечение имени файла
133+
const fileName = path.basename(imagePath);
134+
// Разделение имени файла по разделителю "__"
135+
const parts = fileName.split('__');
136+
if (parts.length !== 2) {
137+
console.warn(`File name format is incorrect: ${fileName}`);
138+
return;
139+
}
140+
const dishID = parts[0]; // Левая часть до "__"
141+
const countPart = parts[1].split('.'); // Правая часть (порядковый номер и расширение)
142+
if (countPart.length < 2) {
143+
console.warn(`File name format is incorrect: ${fileName}`);
144+
return;
145+
}
146+
const count = parseInt(countPart[0], 10); // Извлекаем порядковый номер (число)
147+
if (isNaN(count)) {
148+
console.warn(`File name format is incorrect: ${fileName}`);
149+
return;
150+
}
151+
// Проверка существования файла
132152
if (await fs_1.fsw.exists(imagePath)) {
133-
this.loadImage(imagePath);
153+
await this.loadImage(imagePath, dishID, count);
134154
}
135155
else {
136156
console.warn(`Image not found: ${imagePath}`);
137157
}
138158
}
139159
// Simulate loading an image
140-
loadImage(imagePath) {
160+
async loadImage(imagePath, dishId, sortOrder) {
141161
console.log(`Loading image: ${imagePath}`);
162+
const model = 'dish';
163+
const mfAdater = await Adapter.getMediaFileAdapter();
164+
const mediaFileImage = await mfAdater.toProcess(`file://${imagePath}`, model, "image");
165+
let init = {};
166+
init[`mediafile_${model}`] = mediaFileImage.id;
167+
init[model] = dishId;
168+
init["sortOrder"] = sortOrder;
169+
await SelectedMediaFile.create(init).fetch();
142170
}
143171
// Export images to a directory
144172
async exportImages(dishes, exportDir) {

libs/BackupHandler.ts

+65-29
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,37 @@ export class BackupHandler {
2626
async exportToTar(filePath: string, options: Partial<BackupOptions> = {}): Promise<void> {
2727
try {
2828
const finalOptions = { ...defaultOptions, ...options };
29-
29+
3030
// Получаем текущую директорию для создания временной папки
3131
const currentDir = process.cwd();
32-
32+
3333
// Создаем временную директорию для экспорта
3434
const timestamp = Date.now();
3535
this.workDir = path.join(currentDir, `.tmp/backup-${timestamp}`);
36-
36+
3737
// Создаем папку, если она не существует
3838
await fsw.mkdir(this.workDir);
39-
39+
4040
// Путь для JSON файла
4141
const jsonFilePath = path.join(this.workDir, 'data.json');
42-
42+
4343
// Создание JSON данных
4444
const jsonData = await this.createJSON(finalOptions);
4545
await fsw.writeFile(jsonFilePath, jsonData);
4646

4747
// Экспорт изображений в временную директорию
4848
await this.exportImages(this.dishes, this.workDir);
49-
49+
5050
// Упаковка всего содержимого в tar файл
5151
await this.tar.c({
5252
gzip: true,
5353
file: filePath,
5454
cwd: this.workDir
5555
}, ['.']);
56-
56+
5757
// Удаление временных файлов
5858
await fsw.unlink(jsonFilePath);
59-
59+
6060
console.log('Export completed:', filePath);
6161
} catch (error) {
6262
new Error
@@ -67,46 +67,46 @@ export class BackupHandler {
6767
// Import data and images from a tar file
6868
async importFromTar(filePath: string): Promise<void> {
6969
try {
70-
// Получаем текущую директорию
70+
// Get the current directory
7171
const currentDir = process.cwd();
72-
73-
// Создаем директорию для распаковки
72+
73+
// Create a directory for unpacking
7474
const timestamp = Date.now();
7575
this.workDir = path.join(currentDir, `.tmp/backup-${timestamp}`);
76-
77-
// Создаем папку, если она не существует
76+
77+
// Create a folder if it does not exist
7878
await fsw.mkdir(this.workDir);
79-
79+
8080
console.log(`Extracting tar file to: ${this.workDir}`);
81-
82-
// Распаковываем архив в указанную директорию
81+
82+
// Unpack the archive into the specified directory
8383
await this.tar.x({
8484
file: filePath,
8585
cwd: this.workDir,
8686
});
87-
88-
// Читаем данные JSON
87+
88+
// Reading JSON data
8989
const jsonFilePath = path.join(this.workDir, 'data.json');
9090
const jsonData = await fsw.readFile(jsonFilePath);
9191
const importedData = JSON.parse(jsonData);
92-
92+
9393
this.groups = importedData.groups;
9494
this.dishes = importedData.dishes;
95-
96-
// Проверяем и загружаем изображения
95+
96+
// Checking and uploading images
9797
for (const dish of this.dishes) {
9898
if (dish.images && Array.isArray(dish.images)) {
9999
let count = 1;
100100
for (const image of dish.images) {
101101
const ext = path.extname(image.originalFilePath) || '.webp';
102-
const imagePath = path.join(this.workDir, `${dish.id}_${count}${ext}`);
102+
const imagePath = path.join(this.workDir, `${dish.id}__${count}${ext}`);
103103
this.checkAndLoadImage(imagePath);
104104
count++;
105105
}
106106
}
107107
}
108108

109-
109+
110110
console.log('Import completed:', filePath);
111111
} catch (error) {
112112
console.error('Import error:', error);
@@ -134,23 +134,59 @@ export class BackupHandler {
134134

135135
// Check file existence and load image
136136
private async checkAndLoadImage(imagePath: string): Promise<void> {
137+
// Извлечение имени файла
138+
const fileName = path.basename(imagePath);
139+
140+
// Разделение имени файла по разделителю "__"
141+
const parts = fileName.split('__');
142+
if (parts.length !== 2) {
143+
console.warn(`File name format is incorrect: ${fileName}`);
144+
return;
145+
}
146+
147+
const dishID = parts[0]; // Левая часть до "__"
148+
const countPart = parts[1].split('.'); // Правая часть (порядковый номер и расширение)
149+
150+
if (countPart.length < 2) {
151+
console.warn(`File name format is incorrect: ${fileName}`);
152+
return;
153+
}
154+
155+
const count = parseInt(countPart[0], 10); // Извлекаем порядковый номер (число)
156+
if (isNaN(count)) {
157+
console.warn(`File name format is incorrect: ${fileName}`);
158+
return;
159+
}
160+
161+
// Проверка существования файла
137162
if (await fsw.exists(imagePath)) {
138-
this.loadImage(imagePath);
163+
await this.loadImage(imagePath, dishID, count);
139164
} else {
140165
console.warn(`Image not found: ${imagePath}`);
141166
}
142167
}
143168

169+
144170
// Simulate loading an image
145-
private loadImage(imagePath: string): void {
171+
private async loadImage(imagePath: string, dishId: string, sortOrder: number): Promise<void> {
146172
console.log(`Loading image: ${imagePath}`);
173+
174+
const model = 'dish'
175+
const mfAdater = await Adapter.getMediaFileAdapter();
176+
const mediaFileImage = await mfAdater.toProcess(`file://${imagePath}`, model, "image");
177+
178+
let init: Record<string, string | number> = {};
179+
init[`mediafile_${model}`] = mediaFileImage.id;
180+
init[model] = dishId;
181+
init["sortOrder"] = sortOrder;
182+
await SelectedMediaFile.create(init).fetch();
147183
}
148184

149185
// Export images to a directory
150186
private async exportImages(dishes: DishRecord[], exportDir: string): Promise<void> {
151187
this.workDir = exportDir;
152188
const imagesDir = path.join(this.workDir);
153-
189+
154190
for (const dish of dishes) {
155191
if (dish.images && Array.isArray(dish.images)) {
156192
let count = 1;
@@ -159,19 +195,19 @@ export class BackupHandler {
159195
const ext = path.extname(image.originalFilePath);
160196
const imageFileName = `${dish.id}_${count}${ext}`;
161197
const destinationPath = path.join(imagesDir, imageFileName);
162-
198+
163199
if (await fsw.exists(image.originalFilePath)) {
164200
await fsw.copyFile(image.originalFilePath, destinationPath);
165201
console.log(`Image exported: ${imageFileName}`);
166202
} else {
167203
console.warn(`Image file not found: ${image.originalFilePath}`);
168204
}
169-
205+
170206
count++;
171207
}
172208
}
173209
}
174210
}
175211
}
176-
212+
177213
}

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"author": {
3-
"name": "Webresto team"
3+
"name": "RestoApp team"
44
},
55
"contributors": [
66
{
@@ -79,7 +79,7 @@
7979
"type": "git",
8080
"url": "http://github.com/webresto/core.git"
8181
},
82-
"homepage": "http://webresto.org/",
82+
"homepage": "http://restoapp.org",
8383
"sails": {
8484
"isHook": true,
8585
"hookName": "restocore"
@@ -98,4 +98,4 @@
9898
},
9999
"appId": "restocore",
100100
"version": "2.2.0"
101-
}
101+
}

test/unit/backupHandler/backupHandler.test.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ describe('BackupHandler', () => {
9797
// Check that methods were called
9898
// sinon.assert.calledOnce(tarX); // Check that tar.x was called once
9999
sinon.assert.calledOnce(fsReadFile); // Check that fs.readFile was called once
100-
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-1_1.jpg`); // Check that fs.exists was called with the correct argument
101-
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-2_1.jpg`); // Check that fs.exists was called with the correct argument
100+
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-1__1.jpg`); // Check that fs.exists was called with the correct argument
101+
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-2__1.jpg`); // Check that fs.exists was called with the correct argument
102102
});
103103
it('should generate correct JSON data from createJSON method', async () => {
104104
const backupHandler = new BackupHandler_1.BackupHandler();
@@ -116,8 +116,8 @@ describe('BackupHandler', () => {
116116
// Spy on console.warn
117117
const spy = sinon.spy(console, 'warn');
118118
// Check that a warning appears when an image is not found
119-
await backupHandler['checkAndLoadImage']('nonexistent.jpg'); // await добавлен
120-
sinon.assert.calledWith(spy, 'Image not found: nonexistent.jpg');
119+
await backupHandler['checkAndLoadImage']('/nonexistent__1.jpg'); // await добавлен
120+
sinon.assert.calledWith(spy, 'Image not found: /nonexistent__1.jpg');
121121
spy.restore();
122122
});
123123
it('should export images correctly', async () => {
@@ -130,4 +130,18 @@ describe('BackupHandler', () => {
130130
sinon.assert.calledWith(fsCopyFile, 'image1.jpg', sinon.match.string); // Check that fs.copyFile was called with the expected arguments
131131
sinon.assert.calledWith(fsCopyFile, 'image2.jpg', sinon.match.string); // Check that fs.copyFile was called with the expected arguments
132132
});
133+
it('should load image when file exists', async () => {
134+
const backupHandler = new BackupHandler_1.BackupHandler();
135+
// Mock fs.exists to simulate existing file
136+
fsExists.resolves(true);
137+
// Spy on loadImage method
138+
const loadImageStub = sinon.stub(backupHandler, 'loadImage').resolves();
139+
const imagePath = '/dish:123__4.jpg';
140+
const dishID = "dish:123";
141+
const sortOrder = 4;
142+
// Call checkAndLoadImage
143+
await backupHandler['checkAndLoadImage'](imagePath);
144+
// Check that loadImage was called with the correct arguments
145+
sinon.assert.calledWith(loadImageStub, imagePath, dishID, sortOrder);
146+
});
133147
});

test/unit/backupHandler/backupHandler.test.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ describe('BackupHandler', () => {
8282
// Check that methods were called
8383
// sinon.assert.calledOnce(tarX); // Check that tar.x was called once
8484
sinon.assert.calledOnce(fsReadFile); // Check that fs.readFile was called once
85-
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-1_1.jpg`); // Check that fs.exists was called with the correct argument
86-
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-2_1.jpg`); // Check that fs.exists was called with the correct argument
85+
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-1__1.jpg`); // Check that fs.exists was called with the correct argument
86+
sinon.assert.calledWith(fsExists, `${backupHandler.workDir}/dish-2__1.jpg`); // Check that fs.exists was called with the correct argument
8787
});
8888

8989
it('should generate correct JSON data from createJSON method', async () => {
@@ -108,9 +108,9 @@ describe('BackupHandler', () => {
108108
const spy = sinon.spy(console, 'warn');
109109

110110
// Check that a warning appears when an image is not found
111-
await backupHandler['checkAndLoadImage']('nonexistent.jpg'); // await добавлен
111+
await backupHandler['checkAndLoadImage']('/nonexistent__1.jpg'); // await добавлен
112112

113-
sinon.assert.calledWith(spy, 'Image not found: nonexistent.jpg');
113+
sinon.assert.calledWith(spy, 'Image not found: /nonexistent__1.jpg');
114114

115115
spy.restore();
116116
});
@@ -129,4 +129,24 @@ describe('BackupHandler', () => {
129129
sinon.assert.calledWith(fsCopyFile, 'image1.jpg', sinon.match.string); // Check that fs.copyFile was called with the expected arguments
130130
sinon.assert.calledWith(fsCopyFile, 'image2.jpg', sinon.match.string); // Check that fs.copyFile was called with the expected arguments
131131
});
132+
133+
it('should load image when file exists', async () => {
134+
const backupHandler = new BackupHandler();
135+
136+
// Mock fs.exists to simulate existing file
137+
fsExists.resolves(true);
138+
139+
// Spy on loadImage method
140+
const loadImageStub = sinon.stub(backupHandler as any, 'loadImage').resolves();
141+
142+
const imagePath = '/dish:123__4.jpg';
143+
const dishID = "dish:123";
144+
const sortOrder = 4;
145+
146+
// Call checkAndLoadImage
147+
await backupHandler['checkAndLoadImage'](imagePath);
148+
149+
// Check that loadImage was called with the correct arguments
150+
sinon.assert.calledWith(loadImageStub, imagePath, dishID, sortOrder);
151+
});
132152
});

0 commit comments

Comments
 (0)