mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
64 lines
2.0 KiB
JavaScript
64 lines
2.0 KiB
JavaScript
/*
|
|
* Copyright (c) 2026 by Christian Kellner.
|
|
* Licensed under Apache-2.0 with Commons Clause and Attribution/Naming Clause
|
|
*/
|
|
|
|
import {
|
|
buildBackupFileName,
|
|
createBackupZip,
|
|
precheckRestore,
|
|
restoreFromZip,
|
|
} from '../../services/storage/backupRestoreService.js';
|
|
import { getSettings } from '../../services/storage/settingsStorage.js';
|
|
import { isAdmin } from '../security.js';
|
|
|
|
const DEMO_MODE_ERROR = 'Backup and restore are not available in demo mode.';
|
|
|
|
/**
|
|
* @param {import('fastify').FastifyInstance} fastify
|
|
*/
|
|
export default async function backupPlugin(fastify) {
|
|
// Parse raw binary uploads as Buffer
|
|
fastify.addContentTypeParser(
|
|
['application/zip', 'application/octet-stream'],
|
|
{ parseAs: 'buffer' },
|
|
(req, body, done) => done(null, body),
|
|
);
|
|
|
|
fastify.get('/', async (request, reply) => {
|
|
const settings = await getSettings();
|
|
if (settings.demoMode && !isAdmin(request)) {
|
|
return reply.code(403).send({ error: DEMO_MODE_ERROR });
|
|
}
|
|
const zipBuffer = await createBackupZip();
|
|
const fileName = await buildBackupFileName();
|
|
reply.header('Content-Type', 'application/zip');
|
|
reply.header('Content-Disposition', `attachment; filename="${fileName}"`);
|
|
return reply.send(zipBuffer);
|
|
});
|
|
|
|
fastify.post('/restore', async (request, reply) => {
|
|
const settings = await getSettings();
|
|
if (settings.demoMode && !isAdmin(request)) {
|
|
return reply.code(403).send({ error: DEMO_MODE_ERROR });
|
|
}
|
|
const { dryRun = 'false', force = 'false' } = request.query || {};
|
|
const doDryRun = String(dryRun) === 'true';
|
|
const doForce = String(force) === 'true';
|
|
const body = request.body; // Buffer from addContentTypeParser
|
|
|
|
if (doDryRun) {
|
|
return precheckRestore(body);
|
|
}
|
|
|
|
try {
|
|
return restoreFromZip(body, { force: doForce });
|
|
} catch (e) {
|
|
return reply.code(400).send({
|
|
message: e?.message || 'Restore failed',
|
|
details: e?.payload || null,
|
|
});
|
|
}
|
|
});
|
|
}
|