mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-20 15:24:20 +01:00
I've seen someone who mistakenly had updated their config secret key, not sure if it was done by a weird password manager or a manual action but that did corrupt their entire setup. We now make sure value like secret key get validated before saving. Didn't realise this would be necessary to start with as the appraoch has always been "with great power come great responsability" but if it can prevent catastrophic failure mode hapening by mistake, then we will be making an exception to the moto
97 lines
3.3 KiB
JavaScript
97 lines
3.3 KiB
JavaScript
import { createElement } from "../../lib/skeleton/index.js";
|
|
import rxjs, { effect, applyMutation } from "../../lib/rx.js";
|
|
import { qs, qsa } from "../../lib/dom.js";
|
|
import { createForm, mutateForm } from "../../lib/form.js";
|
|
import { formTmpl } from "../../components/form.js";
|
|
import { generateSkeleton } from "../../components/skeleton.js";
|
|
import { query as getConfig } from "../../model/config.js";
|
|
import ctrlError from "../ctrl_error.js";
|
|
|
|
import { get as getAdminConfig, save as saveConfig, initConfig } from "./model_config.js";
|
|
import { renderLeaf, useForm$, formObjToJSON$ } from "./helper_form.js";
|
|
import transition from "./animate.js";
|
|
import AdminHOC from "./decorator.js";
|
|
|
|
export default AdminHOC(async function(render) {
|
|
const $container = createElement(`
|
|
<div class="component_settingspage sticky">
|
|
<form data-bind="form" class="formbuilder">
|
|
<h2>…</h2>
|
|
${generateSkeleton(10)}
|
|
</form>
|
|
</div>
|
|
`);
|
|
render(transition($container));
|
|
await initConfig();
|
|
|
|
const config$ = getAdminConfig().pipe(
|
|
rxjs.first(),
|
|
reshapeConfigBeforeDisplay,
|
|
);
|
|
|
|
const tmpl = formTmpl({
|
|
renderNode: ({ level, format, label }) => {
|
|
if (level !== 0) return null;
|
|
return createElement(`
|
|
<div>
|
|
<h2>${format(label)}</h2>
|
|
<div data-bind="children"></div>
|
|
</div>
|
|
`);
|
|
},
|
|
renderLeaf,
|
|
autocomplete: false,
|
|
});
|
|
|
|
// feature: setup the form
|
|
const init$ = config$.pipe(
|
|
rxjs.mergeMap((formSpec) => createForm(formSpec, tmpl)),
|
|
rxjs.map(($form) => [$form]),
|
|
applyMutation(qs($container, `[data-bind="form"]`), "replaceChildren"),
|
|
rxjs.share(),
|
|
);
|
|
effect(init$);
|
|
|
|
// feature: handle form change
|
|
effect(init$.pipe(
|
|
useForm$(() => qsa($container, "[data-bind=\"form\"] [name]")),
|
|
rxjs.debounceTime(250),
|
|
rxjs.mergeMap((formState) => config$.pipe(
|
|
rxjs.first(),
|
|
rxjs.map((formSpec) => mutateForm(formSpec, formState)),
|
|
)),
|
|
reshapeConfigBeforeSave,
|
|
saveConfig(),
|
|
rxjs.catchError(ctrlError()),
|
|
));
|
|
});
|
|
|
|
// the config contains stuff wich we don't want to show in this page such as:
|
|
// - the middleware info which is set in the backend page
|
|
// - the connections info which is set in the backend page
|
|
// - the constant info which is for the setup page
|
|
const reshapeConfigBeforeDisplay = rxjs.map((cfg) => {
|
|
const { constant, middleware, connections, ...other } = cfg;
|
|
return other;
|
|
});
|
|
|
|
// before saving things back to the server, we want to hydrate the config and insert back:
|
|
// - the middleware info
|
|
// - the connections info
|
|
const reshapeConfigBeforeSave = rxjs.pipe(
|
|
rxjs.mergeMap((configWithMissingKeys) => getAdminConfig().pipe(
|
|
rxjs.first(),
|
|
rxjs.map((config) => {
|
|
configWithMissingKeys["middleware"] = config["middleware"];
|
|
return configWithMissingKeys;
|
|
}),
|
|
formObjToJSON$(),
|
|
)),
|
|
rxjs.mergeMap((adminConfig) => getConfig().pipe(
|
|
rxjs.first(),
|
|
rxjs.map((publicConfig) => {
|
|
adminConfig["connections"] = publicConfig["connections"];
|
|
return adminConfig;
|
|
}),
|
|
)),
|
|
);
|