import React, { useState, useEffect } from "react"; import { FormBuilder, Icon, Input, Alert, Loader } from "../../components/"; import { Backend, Config, Middleware } from "../../model/"; import { FormObjToJSON, notify, format, createFormBackend, objectGet, JSONStringify } from "../../helpers/"; import { t } from "../../locales/"; import "./backend.scss"; export class BackendPage extends React.Component { constructor(props) { super(props); this.state = { backend_enabled: [], backend_available: {}, auth_enabled: null, auth_available: {}, config: null, isLoading: true, }; } componentDidMount() { Promise.all([ Backend.all(), Config.all(), Middleware.getAllAuthentication(), ]).then((data) => { const [backend, config, middleware_auth] = data; delete config["constants"]; this.setState({ isLoading: false, backend_available: backend, backend_enabled: window.CONFIG["connections"].filter((b) => b).map((conn) => { const f = createFormBackend(backend, conn); if (Object.keys(f).length === 0) { return null; } return f; }).filter((a) => a !== null), config: config, auth_available: middleware_auth, auth_enabled: { // We are storing the config in a fixed schema as we had issues with handling // different schema for each authentication middleware. "identity_provider": (function() { let { type, params } = objectGet(config, ["middleware", "identity_provider"]) || {}; type = objectGet(type, ["value"]); params = objectGet(params, ["value"]); if (!type) return {}; const idpParams = JSON.parse(params); const idpForm = middleware_auth[type] || {}; let key = null; for (key in idpParams) { if (!idpForm[key]) continue; idpForm[key]["value"] = idpParams[key]; } return idpForm; }()), "attribute_mapping": (function(state) { let { related_backend, params = {} } = objectGet(config, ["middleware", "attribute_mapping"]) || {}; related_backend = objectGet(related_backend, ["value"]); params = JSON.parse(objectGet(params, ["value"]) || "{}"); const backendsForm = Object.keys(params).reduce((acc, key) => { const t = createFormBackend( backend, params[key], ); acc[key] = t[params[key]["type"]]; return acc; }, {}); return { "related_backend": { "label": "Related Backend", "type": "text", "description": "List of backends to have behind the authentication process. Can be either a backend type of the actual label", "placeholder": "eg: ftp,sftp,webdav", "readonly": false, "default": null, "value": related_backend, "multi": true, "datalist": window.CONFIG["connections"].map((r) => r.label), "required": true, }, ...backendsForm, }; })(), }, }); }); } componentWillUnmount() { this.props.isSaving(false); Config.clear(); } refresh() { // refresh the screen to refresh the mutation // that have happenned down the stack which react couldn't detect directly this.setState({ refresh: Math.random() }); } _buildConfig() { const json = FormObjToJSON(this.state.config); json.connections = this.state.backend_enabled.map((backend) => { const data = FormObjToJSON(backend, (obj, key) => { if (obj[key].enabled === true) { obj[key] = obj[key].value || obj[key].default; } else { delete obj[key]; } }); const key = Object.keys(data)[0]; return data[key]; }); return json; } onUpdateStorageBackend(e) { this.refresh(); const json = this._buildConfig(); this.props.isSaving(true); return Config.save(json, true, () => { this.props.isSaving(false); }, (err) => { notify.send(err && err.message || t("Oops"), "error"); this.props.isSaving(false); }); } onUpdateAuthenticationMiddleware(middlewareData = null) { this.refresh(); const json = this._buildConfig(); json["middleware"] = { "identity_provider": (function() { const { type, ...other } = objectGet(middlewareData, ["identity_provider"]) || {}; return { "type": type || null, "params": JSONStringify(other), }; })(), "attribute_mapping": (function() { let { related_backend = null, ...params } = objectGet(middlewareData, ["attribute_mapping"]) || {}; const obj = { "related_backend": related_backend || "nop" }; if(Object.keys(params).length > 0) { obj.params = JSONStringify(params); } return obj; })(), }; this.props.isSaving(true); return Config.save(json, true, () => { this.props.isSaving(false); }, (err) => { notify.send(err && err.message || t("Oops"), "error"); this.props.isSaving(false); }); } addBackend(backend_id) { this.setState({ backend_enabled: this.state.backend_enabled.concat( createFormBackend(this.state.backend_available, { type: backend_id, label: function() { const existingLabels = this.state.backend_enabled .filter((b) => !!b[backend_id]) .map((b) => b[backend_id]["label"]["value"]); for (let i=1; i<=existingLabels.length; i++) { const desiredLabel = backend_id.toUpperCase() + i; if (existingLabels.indexOf(desiredLabel) === -1) { return desiredLabel; } } return backend_id.toUpperCase(); }.bind(this)(), }), ), }, this.onUpdateStorageBackend.bind(this)); } removeBackend(n) { this.setState({ backend_enabled: this.state.backend_enabled.filter((_, i) => i !== n), }, this.onUpdateStorageBackend.bind(this)); } changeAuthentication(auth) { this.setState({ auth_enabled: { "identity_provider": auth === null ? {} : this.state.auth_available[auth], "attribute_mapping": objectGet(this.state.auth_enabled, ["attribute_mapping"]) || {}, }, }, () => { this.onUpdateAuthenticationMiddleware(FormObjToJSON(this.state.auth_enabled)); }); } render() { const formRender = ($input, props, struct, onChange) => { if (struct.type === "enable") { // toggle buttons is to hide info from the login page // in this screen, we don't want users to have to click through too many things return null; } return ( ); }; return (