backup fix hotfix

This commit is contained in:
CyferShepard
2025-02-04 16:32:34 +02:00
parent d2aed2e0cf
commit 6bfaaa74e4
2 changed files with 61 additions and 79 deletions

View File

@@ -1,19 +1,19 @@
const express = require('express'); const express = require("express");
const { Pool } = require('pg'); const { Pool } = require("pg");
const fs = require('fs'); const fs = require("fs");
const path = require('path'); const path = require("path");
const { randomUUID } = require('crypto'); const { randomUUID } = require("crypto");
const multer = require('multer'); const multer = require("multer");
const Logging = require('../classes/logging'); const Logging = require("../classes/logging");
const backup = require('../classes/backup'); const backup = require("../classes/backup");
const triggertype = require('../logging/triggertype'); const triggertype = require("../logging/triggertype");
const taskstate = require('../logging/taskstate'); const taskstate = require("../logging/taskstate");
const taskName = require('../logging/taskName'); const taskName = require("../logging/taskName");
const sanitizeFilename = require('../utils/sanitizer'); const sanitizeFilename = require("../utils/sanitizer");
const { sendUpdate } = require('../ws'); const { sendUpdate } = require("../ws");
const db = require('../db'); const db = require("../db");
const router = express.Router(); const router = express.Router();
@@ -22,14 +22,14 @@ const postgresUser = process.env.POSTGRES_USER;
const postgresPassword = process.env.POSTGRES_PASSWORD; const postgresPassword = process.env.POSTGRES_PASSWORD;
const postgresIp = process.env.POSTGRES_IP; const postgresIp = process.env.POSTGRES_IP;
const postgresPort = process.env.POSTGRES_PORT; const postgresPort = process.env.POSTGRES_PORT;
const postgresDatabase = process.env.POSTGRES_DB || 'jfstat'; const postgresDatabase = process.env.POSTGRES_DB || "jfstat";
const backupfolder = 'backup-data'; const backupfolder = "backup-data";
// Restore function // Restore function
function readFile(path) { function readFile(path) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => { fs.readFile(path, "utf8", (err, data) => {
if (err) { if (err) {
reject(err); reject(err);
return; return;
@@ -41,10 +41,10 @@ function readFile(path) {
} }
async function restore(file, refLog) { async function restore(file, refLog) {
refLog.logData.push({ color: 'lawngreen', Message: 'Starting Restore' }); refLog.logData.push({ color: "lawngreen", Message: "Starting Restore" });
refLog.logData.push({ refLog.logData.push({
color: 'yellow', color: "yellow",
Message: 'Restoring from Backup: ' + file, Message: "Restoring from Backup: " + file,
}); });
const pool = new Pool({ const pool = new Pool({
user: postgresUser, user: postgresUser,
@@ -63,7 +63,7 @@ async function restore(file, refLog) {
jsonData = await readFile(backupPath); jsonData = await readFile(backupPath);
} catch (err) { } catch (err) {
refLog.logData.push({ refLog.logData.push({
color: 'red', color: "red",
key: tableName, key: tableName,
Message: `Failed to read backup file`, Message: `Failed to read backup file`,
}); });
@@ -73,7 +73,7 @@ async function restore(file, refLog) {
// console.log(jsonData); // console.log(jsonData);
if (!jsonData) { if (!jsonData) {
console.log('No Data'); console.log("No Data");
return; return;
} }
@@ -81,38 +81,38 @@ async function restore(file, refLog) {
const data = Object.values(table)[0]; const data = Object.values(table)[0];
const tableName = Object.keys(table)[0]; const tableName = Object.keys(table)[0];
refLog.logData.push({ refLog.logData.push({
color: 'dodgerblue', color: "dodgerblue",
key: tableName, key: tableName,
Message: `Restoring ${tableName}`, Message: `Restoring ${tableName}`,
}); });
for (let index in data) { for (let index in data) {
const keysWithQuotes = Object.keys(data[index]).map(key => `"${key}"`); const keysWithQuotes = Object.keys(data[index]).map((key) => `"${key}"`);
const keyString = keysWithQuotes.join(', '); const keyString = keysWithQuotes.join(", ");
const valuesWithQuotes = Object.values(data[index]).map(col => { const valuesWithQuotes = Object.values(data[index]).map((col) => {
if (col === null) { if (col === null) {
return 'NULL'; return "NULL";
} else if (typeof col === 'string') { } else if (typeof col === "string") {
return `'${col.replace(/'/g, "''")}'`; return `'${col.replace(/'/g, "''")}'`;
} else if (typeof col === 'object') { } else if (typeof col === "object") {
return `'${JSON.stringify(col).replace(/'/g, "''")}'`; return `'${JSON.stringify(col).replace(/'/g, "''")}'`;
} else { } else {
return `'${col}'`; return `'${col}'`;
} }
}); });
const valueString = valuesWithQuotes.join(', '); const valueString = valuesWithQuotes.join(", ");
const query = `INSERT INTO ${tableName} (${keyString}) VALUES(${valueString}) ON CONFLICT DO NOTHING`; const query = `INSERT INTO ${tableName} (${keyString}) VALUES(${valueString}) ON CONFLICT DO NOTHING`;
const { rows } = await pool.query(query); const { rows } = await pool.query(query);
} }
} }
await pool.end(); await pool.end();
refLog.logData.push({ color: 'lawngreen', Message: 'Restore Complete' }); refLog.logData.push({ color: "lawngreen", Message: "Restore Complete" });
} }
// Route handler for backup endpoint // Route handler for backup endpoint
router.get('/beginBackup', async (req, res) => { router.get("/beginBackup", async (req, res) => {
try { try {
const last_execution = await db const last_execution = await db
.query( .query(
@@ -122,11 +122,11 @@ router.get('/beginBackup', async (req, res) => {
ORDER BY "TimeRun" DESC ORDER BY "TimeRun" DESC
LIMIT 1` LIMIT 1`
) )
.then(res => res.rows); .then((res) => res.rows);
if (last_execution.length !== 0) { if (last_execution.length !== 0) {
if (last_execution[0].Result === taskstate.RUNNING) { if (last_execution[0].Result === taskstate.RUNNING) {
sendUpdate('TaskError', 'Error: Backup is already running'); sendUpdate("TaskError", "Error: Backup is already running");
res.send(); res.send();
return; return;
} }
@@ -137,50 +137,44 @@ router.get('/beginBackup', async (req, res) => {
await Logging.insertLog(uuid, triggertype.Manual, taskName.backup); await Logging.insertLog(uuid, triggertype.Manual, taskName.backup);
await backup(refLog); await backup(refLog);
Logging.updateLog(uuid, refLog.logData, taskstate.SUCCESS); Logging.updateLog(uuid, refLog.logData, taskstate.SUCCESS);
res.send('Backup completed successfully'); res.send("Backup completed successfully");
sendUpdate('TaskComplete', { message: triggertype + ' Backup Completed' }); sendUpdate("TaskComplete", { message: triggertype + " Backup Completed" });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).send('Backup failed'); res.status(500).send("Backup failed");
} }
}); });
router.get('/restore/:filename', async (req, res) => { router.get("/restore/:filename", async (req, res) => {
try { try {
const uuid = randomUUID(); const uuid = randomUUID();
let refLog = { logData: [], uuid: uuid }; let refLog = { logData: [], uuid: uuid };
Logging.insertLog(uuid, triggertype.Manual, taskName.restore); Logging.insertLog(uuid, triggertype.Manual, taskName.restore);
const filename = sanitizeFilename(req.params.filename); const filename = sanitizeFilename(req.params.filename);
const filePath = path.join( const filePath = path.join(__dirname, "..", backupfolder, filename);
process.cwd(),
__dirname,
'..',
backupfolder,
filename
);
await restore(filePath, refLog); await restore(filePath, refLog);
Logging.updateLog(uuid, refLog.logData, taskstate.SUCCESS); Logging.updateLog(uuid, refLog.logData, taskstate.SUCCESS);
res.send('Restore completed successfully'); res.send("Restore completed successfully");
sendUpdate('TaskComplete', { message: 'Restore completed successfully' }); sendUpdate("TaskComplete", { message: "Restore completed successfully" });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).send('Restore failed'); res.status(500).send("Restore failed");
} }
}); });
router.get('/files', (req, res) => { router.get("/files", (req, res) => {
try { try {
const directoryPath = path.join(__dirname, '..', backupfolder); const directoryPath = path.join(__dirname, "..", backupfolder);
fs.readdir(directoryPath, (err, files) => { fs.readdir(directoryPath, (err, files) => {
if (err) { if (err) {
res.status(500).send('Unable to read directory'); res.status(500).send("Unable to read directory");
} else { } else {
const fileData = files const fileData = files
.filter(file => file.endsWith('.json')) .filter((file) => file.endsWith(".json"))
.map(file => { .map((file) => {
const filePath = path.join(directoryPath, file); const filePath = path.join(directoryPath, file);
const stats = fs.statSync(filePath); const stats = fs.statSync(filePath);
return { return {
@@ -198,34 +192,22 @@ router.get('/files', (req, res) => {
}); });
//download backup file //download backup file
router.get('/files/:filename', (req, res) => { router.get("/files/:filename", (req, res) => {
const filename = sanitizeFilename(req.params.filename); const filename = sanitizeFilename(req.params.filename);
const filePath = path.join( const filePath = path.join(__dirname, "..", backupfolder, filename);
process.cwd(),
__dirname,
'..',
backupfolder,
filename
);
res.download(filePath); res.download(filePath);
}); });
//delete backup //delete backup
router.delete('/files/:filename', (req, res) => { router.delete("/files/:filename", (req, res) => {
try { try {
const filename = sanitizeFilename(req.params.filename); const filename = sanitizeFilename(req.params.filename);
const filePath = path.join( const filePath = path.join(__dirname, "..", backupfolder, filename);
process.cwd(),
__dirname,
'..',
backupfolder,
filename
);
fs.unlink(filePath, err => { fs.unlink(filePath, (err) => {
if (err) { if (err) {
console.error(err); console.error(err);
res.status(500).send('An error occurred while deleting the file.'); res.status(500).send("An error occurred while deleting the file.");
return; return;
} }
@@ -233,13 +215,13 @@ router.delete('/files/:filename', (req, res) => {
res.status(200).send(`${filePath} has been deleted.`); res.status(200).send(`${filePath} has been deleted.`);
}); });
} catch (error) { } catch (error) {
res.status(500).send('An error occurred while deleting the file.'); res.status(500).send("An error occurred while deleting the file.");
} }
}); });
const storage = multer.diskStorage({ const storage = multer.diskStorage({
destination: function (req, file, cb) { destination: function (req, file, cb) {
cb(null, path.join(__dirname, '..', backupfolder)); // Set the destination folder for uploaded files cb(null, path.join(__dirname, "..", backupfolder)); // Set the destination folder for uploaded files
}, },
filename: function (req, file, cb) { filename: function (req, file, cb) {
cb(null, file.originalname); // Set the file name cb(null, file.originalname); // Set the file name
@@ -248,7 +230,7 @@ const storage = multer.diskStorage({
const upload = multer({ storage: storage }); const upload = multer({ storage: storage });
router.post('/upload', upload.single('file'), (req, res) => { router.post("/upload", upload.single("file"), (req, res) => {
// Handle the uploaded file here // Handle the uploaded file here
res.json({ res.json({
fileName: req.file.originalname, fileName: req.file.originalname,
@@ -258,7 +240,7 @@ router.post('/upload', upload.single('file'), (req, res) => {
// Handle other routes // Handle other routes
router.use((req, res) => { router.use((req, res) => {
res.status(404).send({ error: 'Not Found' }); res.status(404).send({ error: "Not Found" });
}); });
module.exports = router; module.exports = router;

View File

@@ -1,7 +1,7 @@
const sanitizer = require("sanitize-filename"); const sanitizeFilename = require("sanitize-filename");
const sanitizeFilename = (filename) => { const sanitizeFile = (filename) => {
return sanitizer(filename); return sanitizeFilename(filename);
}; };
module.export = { sanitizeFilename }; module.exports = sanitizeFile;