mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cabef973a2 |
@@ -9,6 +9,10 @@ import {
|
|||||||
precheckRestore,
|
precheckRestore,
|
||||||
restoreFromZip,
|
restoreFromZip,
|
||||||
} from '../../services/storage/backupRestoreService.js';
|
} 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
|
* @param {import('fastify').FastifyInstance} fastify
|
||||||
@@ -21,7 +25,11 @@ export default async function backupPlugin(fastify) {
|
|||||||
(req, body, done) => done(null, body),
|
(req, body, done) => done(null, body),
|
||||||
);
|
);
|
||||||
|
|
||||||
fastify.get('/', async (_request, reply) => {
|
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 zipBuffer = await createBackupZip();
|
||||||
const fileName = await buildBackupFileName();
|
const fileName = await buildBackupFileName();
|
||||||
reply.header('Content-Type', 'application/zip');
|
reply.header('Content-Type', 'application/zip');
|
||||||
@@ -30,6 +38,10 @@ export default async function backupPlugin(fastify) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
fastify.post('/restore', async (request, reply) => {
|
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 { dryRun = 'false', force = 'false' } = request.query || {};
|
||||||
const doDryRun = String(dryRun) === 'true';
|
const doDryRun = String(dryRun) === 'true';
|
||||||
const doForce = String(force) === 'true';
|
const doForce = String(force) === 'true';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fredy",
|
"name": "fredy",
|
||||||
"version": "22.0.3",
|
"version": "22.0.4",
|
||||||
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ const GeneralSettings = function GeneralSettings() {
|
|||||||
const [loading, setLoading] = React.useState(true);
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
|
||||||
const settings = useSelector((state) => state.generalSettings.settings);
|
const settings = useSelector((state) => state.generalSettings.settings);
|
||||||
|
const currentUser = useSelector((state) => state.user.currentUser);
|
||||||
|
|
||||||
const [interval, setInterval] = React.useState('');
|
const [interval, setInterval] = React.useState('');
|
||||||
const [port, setPort] = React.useState('');
|
const [port, setPort] = React.useState('');
|
||||||
@@ -467,12 +468,26 @@ const GeneralSettings = function GeneralSettings() {
|
|||||||
itemKey="backup"
|
itemKey="backup"
|
||||||
>
|
>
|
||||||
<div className="generalSettings__tab-content">
|
<div className="generalSettings__tab-content">
|
||||||
|
{demoMode && !currentUser?.isAdmin && (
|
||||||
|
<Banner
|
||||||
|
fullMode={false}
|
||||||
|
type="warning"
|
||||||
|
closeIcon={null}
|
||||||
|
style={{ marginBottom: '12px' }}
|
||||||
|
description="Backup and restore are not available in demo mode."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<SegmentPart
|
<SegmentPart
|
||||||
name="Backup & Restore"
|
name="Backup & Restore"
|
||||||
helpText="Download a zipped backup of your database or restore from a backup zip."
|
helpText="Download a zipped backup of your database or restore from a backup zip."
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||||
<Button theme="solid" icon={<IconSave />} onClick={handleDownloadBackup}>
|
<Button
|
||||||
|
theme="solid"
|
||||||
|
icon={<IconSave />}
|
||||||
|
onClick={handleDownloadBackup}
|
||||||
|
disabled={demoMode && !currentUser?.isAdmin}
|
||||||
|
>
|
||||||
Download Backup
|
Download Backup
|
||||||
</Button>
|
</Button>
|
||||||
<input
|
<input
|
||||||
@@ -482,7 +497,12 @@ const GeneralSettings = function GeneralSettings() {
|
|||||||
style={{ display: 'none' }}
|
style={{ display: 'none' }}
|
||||||
onChange={handleSelectRestoreFile}
|
onChange={handleSelectRestoreFile}
|
||||||
/>
|
/>
|
||||||
<Button onClick={handleOpenFilePicker} theme="light" icon={<IconFolder />}>
|
<Button
|
||||||
|
onClick={handleOpenFilePicker}
|
||||||
|
theme="light"
|
||||||
|
icon={<IconFolder />}
|
||||||
|
disabled={demoMode && !currentUser?.isAdmin}
|
||||||
|
>
|
||||||
Restore from Zip
|
Restore from Zip
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user