ебать что это блять
This commit is contained in:
102
src/services/backups.js
Normal file
102
src/services/backups.js
Normal file
@@ -0,0 +1,102 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const BACKUPS_DIR = path.join(__dirname, '..', '..', 'backups');
|
||||
const USERS_FILE = path.join(__dirname, '..', '..', 'users.json');
|
||||
const AUDIT_LOG_FILE = path.join(__dirname, '..', '..', 'audit.log');
|
||||
|
||||
function ensureBackupsDir() {
|
||||
fs.mkdirSync(BACKUPS_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
function makeBackupFilename() {
|
||||
const now = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
return `backup-${now}.json`;
|
||||
}
|
||||
|
||||
async function createBackup(pool, actor = 'system') {
|
||||
ensureBackupsDir();
|
||||
|
||||
const tablesResult = await pool.query(`
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
ORDER BY table_name
|
||||
`);
|
||||
|
||||
const tables = [];
|
||||
for (const row of tablesResult.rows) {
|
||||
const tableName = row.table_name;
|
||||
const structure = await pool.query(`
|
||||
SELECT
|
||||
c.column_name AS name,
|
||||
c.data_type AS type,
|
||||
c.is_nullable AS nullable,
|
||||
c.column_default AS default_value
|
||||
FROM information_schema.columns c
|
||||
WHERE c.table_name = $1 AND c.table_schema = 'public'
|
||||
ORDER BY c.ordinal_position
|
||||
`, [tableName]);
|
||||
const data = await pool.query(`SELECT * FROM "${tableName}"`);
|
||||
tables.push({
|
||||
name: tableName,
|
||||
structure: structure.rows,
|
||||
rows: data.rows,
|
||||
});
|
||||
}
|
||||
|
||||
const backup = {
|
||||
meta: {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: actor,
|
||||
version: 1,
|
||||
},
|
||||
users: fs.existsSync(USERS_FILE) ? JSON.parse(fs.readFileSync(USERS_FILE, 'utf8')) : { users: [] },
|
||||
audit: fs.existsSync(AUDIT_LOG_FILE)
|
||||
? fs.readFileSync(AUDIT_LOG_FILE, 'utf8').split(/\r?\n/).filter(Boolean)
|
||||
: [],
|
||||
tables,
|
||||
};
|
||||
|
||||
const filename = makeBackupFilename();
|
||||
const filePath = path.join(BACKUPS_DIR, filename);
|
||||
fs.writeFileSync(filePath, JSON.stringify(backup, null, 2), 'utf8');
|
||||
|
||||
return {
|
||||
filename,
|
||||
filePath,
|
||||
size: fs.statSync(filePath).size,
|
||||
createdAt: backup.meta.createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
function listBackups() {
|
||||
ensureBackupsDir();
|
||||
return fs.readdirSync(BACKUPS_DIR)
|
||||
.filter((name) => name.endsWith('.json'))
|
||||
.map((name) => {
|
||||
const filePath = path.join(BACKUPS_DIR, name);
|
||||
const stats = fs.statSync(filePath);
|
||||
return {
|
||||
filename: name,
|
||||
size: stats.size,
|
||||
createdAt: stats.birthtime.toISOString(),
|
||||
};
|
||||
})
|
||||
.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
||||
}
|
||||
|
||||
function getBackupPath(filename) {
|
||||
const filePath = path.join(BACKUPS_DIR, filename);
|
||||
if (!filePath.startsWith(BACKUPS_DIR) || !fs.existsSync(filePath)) {
|
||||
throw new Error('Backup not found');
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
BACKUPS_DIR,
|
||||
createBackup,
|
||||
getBackupPath,
|
||||
listBackups,
|
||||
};
|
||||
Reference in New Issue
Block a user