From eb2e1ee027b9003d6471b7cde66933505bbc4829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Banno-Cloutier?= <leo.banno-cloutier@savoirfairelinux.com> Date: Tue, 20 Jun 2023 14:00:50 -0400 Subject: [PATCH] jams-react-client: add PolicyDataContext Change-Id: I315a0b4c71661e1b7c9fd4e3f9261e4e7ad68078 --- .dockerignore | 1 + .../src/views/Blueprint/Blueprint.js | 3 + .../Blueprint/EditBlueprintConfiguration.js | 259 ++---------------- .../Blueprint/EditBlueprintPermissions.js | 238 +++------------- .../src/views/Blueprint/EditBlueprintUi.js | 180 ++---------- .../src/views/Blueprint/PolicyDataContext.js | 61 +++++ .../src/views/Blueprint/parsePolicyData.js | 101 +++++++ .../views/Blueprint/policyData.constants.js | 39 +++ .../src/views/Blueprint/updatePolicyData.js | 168 ++++++++++++ 9 files changed, 452 insertions(+), 598 deletions(-) create mode 100644 jams-react-client/src/views/Blueprint/PolicyDataContext.js create mode 100644 jams-react-client/src/views/Blueprint/parsePolicyData.js create mode 100644 jams-react-client/src/views/Blueprint/policyData.constants.js create mode 100644 jams-react-client/src/views/Blueprint/updatePolicyData.js diff --git a/.dockerignore b/.dockerignore index e4c71e6e..56e5249f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,5 +4,6 @@ .dockerignore **/node_modules +**/target jams diff --git a/jams-react-client/src/views/Blueprint/Blueprint.js b/jams-react-client/src/views/Blueprint/Blueprint.js index 72283bca..ecf1a1fc 100644 --- a/jams-react-client/src/views/Blueprint/Blueprint.js +++ b/jams-react-client/src/views/Blueprint/Blueprint.js @@ -10,6 +10,7 @@ import Box from "@material-ui/core/Box"; import EditBlueprintPermissions from "./EditBlueprintPermissions"; import EditBlueprintConfiguration from "./EditBlueprintConfiguration"; import EditBlueprintUi from "./EditBlueprintUi"; +import { PolicyDataContextProvider } from "./PolicyDataContext"; import { infoColor } from "assets/jss/material-dashboard-react.js"; @@ -78,6 +79,7 @@ export default function Blueprint({ blueprintName }) { </Tabs> </AppBar> + <PolicyDataContextProvider blueprintName={blueprintName}> <TabPanel value={openedTab} index={0}> <EditBlueprintPermissions blueprintName={blueprintName} /> </TabPanel> @@ -87,6 +89,7 @@ export default function Blueprint({ blueprintName }) { <TabPanel value={openedTab} index={2}> <EditBlueprintUi blueprintName={blueprintName} /> </TabPanel> + </PolicyDataContextProvider> </div> ); } diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js b/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js index 4192bcfd..7017a89f 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js +++ b/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useContext, useState } from "react"; import clsx from "clsx"; // @material-ui/core components @@ -41,6 +41,7 @@ import { hexToRgb, blackColor } from "assets/jss/material-dashboard-react.js"; import BlueprintSnackbar from "components/Snackbar/BlueprintSnackbar"; import CustomPopupState from "components/CustomPopupState/CustomPopupState"; +import { PolicyDataContext } from "./PolicyDataContext"; const styles = (theme) => ({ ...dashboardStyle, @@ -158,214 +159,30 @@ const StyledRadio = (props) => { export default function EditBlueprintConfiguration(props) { const classes = useStyles(); - - const [videoEnabled, setVideoEnabled] = useState(true); - const [publicInCalls, setPublicInCalls] = useState(true); - const [autoAnswer, setAutoAnswer] = useState(false); - const [peerDiscovery, setPeerDiscovery] = useState(true); - const [rendezVous, setRendezVous] = useState(false); - - const [selectedTurnOption, setSelectedTurnOption] = useState("defaultTurn"); - const [selectedDHTProxyOption, setSelectedDHTProxyOption] = useState( - "defaultDHTProxy" + const { policyData, updatePolicyData, snackbar, setSnackbar } = useContext( + PolicyDataContext ); - const [upnpEnabled, setUpnpEnabled] = useState(true); - const [turnEnabled, setTurnEnabled] = useState(true); - const [turnServer, setTurnServer] = useState("turn.jami.net"); - const [turnServerUserName, setTurnServerUserName] = useState("ring"); - const [turnServerPassword, setTurnServerPassword] = useState("ring"); - const [proxyEnabled, setProxyEnabled] = useState(false); - const [proxyServer, setProxyServer] = useState("dhtproxy.jami.net"); - const [dhtProxyListUrl, setDhtProxyListUrl] = useState(""); - - const [turnPassowrdVisible, setTurnPasswordVisible] = useState(false); - - const [uiCustomization, setUiCustomization] = useState(""); - - const [open, setOpen] = useState(false); - const [message, setMessage] = useState(false); - const [severity, setSeverity] = useState("success"); - - const [getRequestDone, setGetRequestDone] = useState(false); - - useEffect(() => { - axios( - configApiCall( - api_path_blueprints + "?name=" + props.blueprintName, - "GET", - null, - null - ) - ) - .then((response) => { - let policyData = JSON.parse(response.data.policyData); - setVideoEnabled(policyData["videoEnabled"]); - setPublicInCalls(policyData["publicInCalls"]); - setAutoAnswer(policyData["autoAnswer"]); - setPeerDiscovery(policyData["peerDiscovery"]); - setRendezVous(policyData["rendezVous"]); - setUiCustomization(policyData["uiCustomization"]); - - setUpnpEnabled(policyData["upnpEnabled"]); - if (policyData["turnEnabled"] === true) { - setSelectedTurnOption("customTurn"); - setTurnEnabled(policyData["turnEnabled"]); - setTurnServer(policyData["turnServer"]); - setTurnServerUserName(policyData["turnServerUserName"]); - setTurnServerPassword(policyData["turnServerPassword"]); - } else if (policyData["turnEnabled"] === false) { - setSelectedTurnOption("disabledTurn"); - setTurnEnabled(false); - } else { - setSelectedTurnOption("defaultTurn"); - } - if (policyData["proxyEnabled"] === true) { - setSelectedDHTProxyOption("customDHTProxy"); - setProxyEnabled(policyData["proxyEnabled"]); - setProxyServer(policyData["proxyServer"]); - setDhtProxyListUrl(policyData["dhtProxyListUrl"]); - } else if (policyData["proxyEnabled"] === false) { - setSelectedDHTProxyOption("disabledDHTProxy"); - setTurnEnabled(false); - } else { - setSelectedDHTProxyOption("defaultDHTProxy"); - } - }) - .catch((error) => { - console.log( - "Error fetching blueprint permissions : " + - props.username + - " " + - error - ); - }) - .finally(() => { - setGetRequestDone(true); - }); - }, [props.blueprintName, props.username]); - const handleUpdateConfiguration = (field, value, selectedOptions = []) => { - // if the get request is not done yet, don't update the configuration - if (!getRequestDone) { - return; - } + const { + upnpEnabled, - let data = { - videoEnabled: videoEnabled, - publicInCalls: publicInCalls, - autoAnswer: autoAnswer, - peerDiscovery: peerDiscovery, - accountDiscovery: peerDiscovery, - accountPublish: peerDiscovery, - rendezVous: rendezVous, - upnpEnabled: upnpEnabled, - turnEnabled: turnEnabled, - turnServer: turnServer, - turnServerUserName: turnServerUserName, - turnServerPassword: turnServerPassword, - proxyEnabled: proxyEnabled, - proxyServer: proxyServer, - dhtProxyListUrl: dhtProxyListUrl, - uiCustomization: uiCustomization, - }; + selectedTurnOption, + turnServer, + turnServerUserName, - data[field] = value; + selectedDHTProxyOption, + proxyServer, + dhtProxyListUrl, + } = policyData; - selectedOptions.forEach((selectedOption) => { - if (selectedOption === "defaultTurn") { - delete data.turnEnabled; - delete data.turnServer; - delete data.turnServerUserName; - delete data.turnServerPassword; - } - - if (selectedOption === "defaultDHTProxy") { - delete data.proxyEnabled; - delete data.proxyServer; - delete data.dhtProxyListUrl; - } - - if (selectedOption === "customTurn") { - data.turnEnabled = true; - } - if (selectedOption === "customDHTProxy") { - data.proxyEnabled = true; - } - - if (selectedOption === "disabledTurn") { - data.turnEnabled = false; - } - if (selectedOption === "disabledDHTProxy") { - data.proxyEnabled = false; - } - }); - - axios( - configApiCall( - api_path_blueprints + "?name=" + props.blueprintName, - "PUT", - data, - null - ) - ) - .then((response) => { - setOpen(false); - setSeverity("success"); - setOpen(true); - setMessage( - i18next.t( - "updated_blueprint_configuration_successfully", - "Blueprint configuration successfully updated." - ) - ); - }) - .catch((error) => { - setOpen(false); - setSeverity("error"); - setOpen(true); - setMessage( - i18next.t( - "error_updating_blueprint_configuration", - "Error occurred while updating blueprint configuration." - ) + - error + - "!" - ); - }); - }; + const [turnPasswordVisible, setTurnPasswordVisible] = useState(false); const handleTurnChangedOption = (event) => { - setSelectedTurnOption(event.target.value); - if (event.target.value === "customTurn") { - setTurnEnabled(true); - handleUpdateConfiguration("turnEnabled", true, [ - event.target.value, - selectedDHTProxyOption, - ]); - } else { - setTurnEnabled(false); - handleUpdateConfiguration("turnEnabled", false, [ - event.target.value, - selectedDHTProxyOption, - ]); - } + updatePolicyData("selectedTurnOption", event.target.value); }; const handleDHTProxyChangedOption = (event) => { - setSelectedDHTProxyOption(event.target.value); - if (event.target.value === "customDHTProxy") { - setProxyEnabled(true); - handleUpdateConfiguration("proxyEnabled", true, [ - selectedTurnOption, - event.target.value, - ]); - } else { - setProxyEnabled(false); - handleUpdateConfiguration("proxyEnabled", false, [ - selectedTurnOption, - event.target.value, - ]); - } + updatePolicyData("selectedDHTProxyOption", event.target.value); }; const handleMouseDownPassword = () => { @@ -410,12 +227,7 @@ export default function EditBlueprintConfiguration(props) { checked={upnpEnabled} color="primary" onChange={(e) => { - setUpnpEnabled(e.target.checked); - handleUpdateConfiguration( - "upnpEnabled", - e.target.checked, - [selectedTurnOption, selectedDHTProxyOption] - ); + updatePolicyData("upnpEnabled", e.target.checked); }} name="upnpEnabled" inputProps={{ "aria-label": "secondary checkbox" }} @@ -482,12 +294,7 @@ export default function EditBlueprintConfiguration(props) { </InputAdornment> } onChange={(e) => { - setTurnServer(e.target.value); - handleUpdateConfiguration( - "turnServer", - e.target.value, - ["customTurn", selectedDHTProxyOption] - ); + updatePolicyData("turnServer", e.target.value); }} /> </FormControl> @@ -517,11 +324,9 @@ export default function EditBlueprintConfiguration(props) { </InputAdornment> } onChange={(e) => { - setTurnServerUserName(e.target.value); - handleUpdateConfiguration( + updatePolicyData( "turnServerUserName", - e.target.value, - ["customTurn", selectedDHTProxyOption] + e.target.value ); }} /> @@ -544,10 +349,9 @@ export default function EditBlueprintConfiguration(props) { )} </InputLabel> <Input - disabled={!turnEnabled} id="turnServerPassword" placeholder="****" - type={turnPassowrdVisible ? "text" : "password"} + type={turnPasswordVisible ? "text" : "password"} startAdornment={ <InputAdornment position="start"> <VpnKeyOutlinedIcon /> @@ -559,7 +363,7 @@ export default function EditBlueprintConfiguration(props) { onMouseDown={handleMouseDownPassword} onMouseUp={handleMouseUpPassword} > - {turnPassowrdVisible ? ( + {turnPasswordVisible ? ( <VisibilityIcon /> ) : ( <VisibilityOffIcon /> @@ -567,11 +371,9 @@ export default function EditBlueprintConfiguration(props) { </IconButton> } onChange={(e) => { - setTurnServerPassword(e.target.value); - handleUpdateConfiguration( + updatePolicyData( "turnServerPassword", - e.target.value, - ["customTurn", selectedDHTProxyOption] + e.target.value ); }} /> @@ -647,12 +449,7 @@ export default function EditBlueprintConfiguration(props) { </InputAdornment> } onChange={(e) => { - setProxyServer(e.target.value); - handleUpdateConfiguration( - "proxyServer", - e.target.value, - [selectedTurnOption, "customDHTProxy"] - ); + updatePolicyData("proxyServer", e.target.value); }} /> </FormControl> @@ -682,11 +479,9 @@ export default function EditBlueprintConfiguration(props) { </InputAdornment> } onChange={(e) => { - setDhtProxyListUrl(e.target.value); - handleUpdateConfiguration( + updatePolicyData( "dhtProxyListUrl", - e.target.value, - [selectedTurnOption, "customDHTProxy"] + e.target.value ); }} /> diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js b/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js index 4d2b9c12..3afd34ac 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js +++ b/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { Link, useHistory } from "react-router-dom"; import axios from "axios"; import i18next from "i18next"; @@ -41,10 +41,9 @@ import auth from "../../auth"; import configApiCall from "../../api"; import { api_path_get_user_directory_search, - api_path_get_ns_name_from_addr, - api_path_get_user_profile, } from "../../globalUrls"; +import { PolicyDataContext } from "./PolicyDataContext"; const styles = { ...dashboardStyle, @@ -103,39 +102,26 @@ const styles = { const useStyles = makeStyles(styles); - export default function EditBlueprintPermissions(props) { const classes = useStyles(); const history = useHistory(); + const { policyData, updatePolicyData, snackbar, setSnackbar } = useContext( + PolicyDataContext + ); const [openDrawer, setOpenDrawer] = useState(false); const [users, setUsers] = useState([]); - const [blueprintModerators, setBlueprintModerators] = useState([]); - - const [videoEnabled, setVideoEnabled] = useState(true); - const [publicInCalls, setPublicInCalls] = useState(true); - const [autoAnswer, setAutoAnswer] = useState(false); - const [peerDiscovery, setPeerDiscovery] = useState(true); - const [rendezVous, setRendezVous] = useState(false); - const [defaultModerators, setDefaultModerators] = useState(""); - - const [upnpEnabled, setUpnpEnabled] = useState(true); - const [turnEnabled, setTurnEnabled] = useState(true); - const [turnServer, setTurnServer] = useState("turn.jami.net"); - const [turnServerUserName, setTurnServerUserName] = useState("ring"); - const [turnServerPassword, setTurnServerPassword] = useState("ring"); - const [proxyEnabled, setProxyEnabled] = useState(false); - const [proxyServer, setProxyServer] = useState("dhtproxy.jami.net"); - const [dhtProxyListUrl, setDhtProxyListUrl] = useState(""); - - const [allowLookup, setAllowLookup] = useState(true); - - const [uiCustomization, setUiCustomization] = useState(""); - const [open, setOpen] = useState(false); - const [message, setMessage] = useState(false); - const [severity, setSeverity] = useState("success"); + const { + videoEnabled, + publicInCalls, + autoAnswer, + peerDiscovery, + rendezVous, + blueprintModerators, + allowLookup, + } = policyData; const searchUsers = (value) => { axios( @@ -147,14 +133,16 @@ export default function EditBlueprintPermissions(props) { ) ) .then((response) => { - let profiles = []; + if (response.status === 204) { + setUsers([]); + return; + } + const profilesResults = response.data.profiles; - profilesResults.forEach((profile) => { - let existingUser = false; - users.forEach((user) => { - if (profile.username === user.username) existingUser = true; - }); - if (!existingUser) profiles.push(profile); + const usernames = users.map((user) => user.username); + + const profiles = profilesResults.filter((profile) => { + return !usernames.includes(profile.username); }); setUsers(profiles); }) @@ -169,167 +157,17 @@ export default function EditBlueprintPermissions(props) { useEffect(() => { searchUsers(); - - axios( - configApiCall( - api_path_blueprints + "?name=" + props.blueprintName, - "GET", - null, - null - ) - ) - .then((response) => { - let policyData = JSON.parse(response.data.policyData); - - setVideoEnabled(policyData["videoEnabled"]); - setPublicInCalls(policyData["publicInCalls"]); - setAutoAnswer(policyData["autoAnswer"]); - setPeerDiscovery(policyData["peerDiscovery"]); - setRendezVous(policyData["rendezVous"]); - setDefaultModerators(policyData["defaultModerators"]); - - setUpnpEnabled(policyData["upnpEnabled"]); - setTurnEnabled(policyData["turnEnabled"]); - setTurnServer(policyData["turnServer"]); - setTurnServerUserName(policyData["turnServerUserName"]); - setTurnServerPassword(policyData["turnServerPassword"]); - setProxyEnabled(policyData["proxyEnabled"]); - setProxyServer(policyData["proxyServer"]); - setDhtProxyListUrl(); - setAllowLookup(policyData["allowLookup"]); - - setUiCustomization(policyData["uiCustomization"]); - - policyData["defaultModerators"].split("/").forEach((id) => { - if (id !== "undefined" && id !== "") { - axios( - configApiCall(api_path_get_ns_name_from_addr + id), - null, - null - ).then((usernameResponse) => { - let username = usernameResponse.data.name; - axios( - configApiCall(api_path_get_user_profile + username), - null, - null - ).then((userProfileResponse) => { - let userProfiles = blueprintModerators; - userProfileResponse.data["id"] = id; - userProfiles.push(userProfileResponse.data); - setBlueprintModerators(userProfiles); - // This state update is added to refresh the list of moderators - setOpenDrawer(true); - setOpenDrawer(false); - }); - }); - } - }); - }) - .catch((error) => { - console.log( - "Error fetching blueprint permissions : " + - props.blueprintName + - " " + - error - ); - }); - }, [props.blueprintName]); - - const handleUpdatePermissions = (field, value) => { - let data = { - videoEnabled: videoEnabled, - publicInCalls: publicInCalls, - autoAnswer: autoAnswer, - peerDiscovery: peerDiscovery, - accountDiscovery: peerDiscovery, - accountPublish: peerDiscovery, - rendezVous: rendezVous, - defaultModerators: defaultModerators, - upnpEnabled: upnpEnabled, - turnEnabled: turnEnabled, - turnServer: turnServer, - turnServerUserName: turnServerUserName, - turnServerPassword: turnServerPassword, - proxyEnabled: proxyEnabled, - proxyServer: proxyServer, - dhtProxyListUrl: dhtProxyListUrl, - allowLookup: allowLookup, - uiCustomization: uiCustomization, - }; - - if (field === "peerDiscovery") { - data.peerDiscovery = value; - data.accountDiscovery = value; - data.accountPublish = value; - } else { - data[field] = value; - } - - if (turnEnabled === undefined) { - delete data.turnEnabled; - delete data.turnServer; - delete data.turnServerUserName; - delete data.turnServerPassword; - } - - if (proxyEnabled === undefined) { - delete data.proxyEnabled; - delete data.proxyServer; - delete data.dhtProxyListUrl; - } - - axios( - configApiCall( - api_path_blueprints + "?name=" + props.blueprintName, - "PUT", - data, - null - ) - ) - .then((response) => { - setOpen(false); - setSeverity("success"); - setOpen(true); - setMessage( - i18next.t( - "updated_blueprint_permissions_successfully", - "Blueprint permissions successfully updated." - ) - ); - }) - .catch((error) => { - setOpen(false); - setSeverity("error"); - setOpen(true); - setMessage( - i18next.t( - "error_updating_blueprint_permissions", - "Error occurred while updating blueprint permissions." - ) + - error + - "!" - ); - }); - }; + }, []); const addModeratorToBlueprint = (user) => { - handleUpdatePermissions( - "defaultModerators", - defaultModerators + user.id + "/" - ); - setDefaultModerators(defaultModerators + user.id + "/"); - let newBlueprintModerators = blueprintModerators; - newBlueprintModerators.push(user); - setBlueprintModerators(newBlueprintModerators); + updatePolicyData("blueprintModerators", [...blueprintModerators, user]); }; const removeModeratorFromBlueprint = (user) => { - let newDefaultModerators = defaultModerators.replace(user.id + "/", ""); - handleUpdatePermissions("defaultModerators", newDefaultModerators); - setDefaultModerators(newDefaultModerators); - let newBlueprintModerators = blueprintModerators; - newBlueprintModerators.splice(newBlueprintModerators.indexOf(user), 1); - setBlueprintModerators(newBlueprintModerators); + const newBlueprintModerators = blueprintModerators.filter( + (moderator) => moderator.id !== user.id + ); + updatePolicyData("blueprintModerators", newBlueprintModerators); }; return ( @@ -377,8 +215,7 @@ export default function EditBlueprintPermissions(props) { checked={videoEnabled} color="primary" onChange={(e) => { - setVideoEnabled(e.target.checked); - handleUpdatePermissions( + updatePolicyData( "videoEnabled", e.target.checked ); @@ -405,8 +242,7 @@ export default function EditBlueprintPermissions(props) { checked={publicInCalls} color="primary" onChange={(e) => { - setPublicInCalls(e.target.checked); - handleUpdatePermissions( + updatePolicyData( "publicInCalls", e.target.checked ); @@ -433,8 +269,7 @@ export default function EditBlueprintPermissions(props) { checked={autoAnswer} color="primary" onChange={(e) => { - setAutoAnswer(e.target.checked); - handleUpdatePermissions( + updatePolicyData( "autoAnswer", e.target.checked ); @@ -466,8 +301,7 @@ export default function EditBlueprintPermissions(props) { checked={peerDiscovery} color="primary" onChange={(e) => { - setPeerDiscovery(e.target.checked); - handleUpdatePermissions( + updatePolicyData( "peerDiscovery", e.target.checked ); @@ -502,8 +336,7 @@ export default function EditBlueprintPermissions(props) { checked={allowLookup} color="primary" onChange={(e) => { - setAllowLookup(e.target.checked); - handleUpdatePermissions( + updatePolicyData( "allowLookup", e.target.checked ); @@ -542,8 +375,7 @@ export default function EditBlueprintPermissions(props) { checked={rendezVous} color="primary" onChange={(e) => { - setRendezVous(e.target.checked); - handleUpdatePermissions("rendezVous", e.target.checked); + updatePolicyData("rendezVous", e.target.checked); }} name="rendezVous" inputProps={{ "aria-label": "secondary checkbox" }} diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintUi.js b/jams-react-client/src/views/Blueprint/EditBlueprintUi.js index 2822a1ea..024b348c 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintUi.js +++ b/jams-react-client/src/views/Blueprint/EditBlueprintUi.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useContext, useState } from "react"; import { makeStyles } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; @@ -14,28 +14,16 @@ import GridContainer from "components/Grid/GridContainer.js"; import { hexToRgb, blackColor } from "assets/jss/material-dashboard-react.js"; -import { api_path_blueprints, api_path_get_image, api_path_post_image } from "../../globalUrls"; +import { api_path_get_image, api_path_post_image } from "../../globalUrls"; import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardStyle.js"; import i18next from "i18next"; + import CustomUiPreview from "components/CustomUiPreview/CustomUiPreview"; import EditBlueprintUiForm from "./EditBlueprintUiForm"; -import configApiCall from "api"; -import axios from "axios"; - -const DEFAULT_UI_CUSTOMIZATION = { - hasTitle: true, - customTitle: "", - hasDescription: true, - customDescription: "", - hasTips: false, - hasBackgroundCustom: false, - customBackgroundColor: "", - customBackgroundImageUrl: "", - hasLogo: true, - customLogoImageUrl: "", -}; +import { DEFAULT_UI_CUSTOMIZATION } from "./policyData.constants"; +import { PolicyDataContext } from "./PolicyDataContext"; const styles = { ...dashboardStyle, @@ -105,89 +93,23 @@ const useStyles = makeStyles(styles); export default function EditBlueprintUi({ blueprintName }) { const classes = useStyles(); - const [policyData, setPolicyData] = useState({ - uiCustomization: DEFAULT_UI_CUSTOMIZATION, - }); - let { uiCustomization } = policyData; + const { policyData, updatePolicyData, snackbar, setSnackbar } = useContext( + PolicyDataContext + ); + const { uiCustomization } = policyData; const setUiCustomization = (ui) => { - setPolicyData({ ...policyData, uiCustomization: ui }); + updatePolicyData("uiCustomization", ui); }; const [oldUiCustomization, setOldUiCustomization] = useState(uiCustomization); const [opacity, setOpacity] = useState(0); - const [open, setOpen] = useState(false); - const [message, setMessage] = useState(false); - const [severity, setSeverity] = useState("success"); - - const [bgFile, setBgFile] = useState(null); - const [logoFile, setLogoFile] = useState(null); - - useEffect(() => { - axios( - configApiCall( - api_path_blueprints + "?name=" + blueprintName, - "GET", - null, - null - ) - ) - .then((response) => { - let policyDataResponse = JSON.parse(response.data.policyData); - policyDataResponse.uiCustomization = JSON.parse( - policyDataResponse.uiCustomization - ); - - setPolicyData(policyDataResponse); - - const { uiCustomization: uiCustomizationResponse } = policyDataResponse; - - if (uiCustomizationResponse) { - if ( - uiCustomizationResponse.customBackgroundImageUrl && - uiCustomizationResponse.hasBackgroundCustom - ) { - //Get the name of the file from the url - let urlParts = uiCustomizationResponse.customBackgroundImageUrl.split( - "/" - ); - if (urlParts.length) { - setBgFile(urlParts[urlParts.length - 1]); - } - } - if ( - uiCustomizationResponse.customLogoImageUrl && - uiCustomizationResponse.hasLogo - ) { - //Get the name of the file from the url - let urlParts = uiCustomizationResponse.customLogoImageUrl.split( - "/" - ); - if (urlParts.length) { - setLogoFile(urlParts[urlParts.length - 1]); - } - } - - // refresh the preview - setOldUiCustomization(uiCustomizationResponse); - console.log("Found ui customization in the policy data"); - } else { - setUiCustomization(DEFAULT_UI_CUSTOMIZATION); - console.log("Did not find ui customization in the policy data"); - } - }) - .catch((error) => { - setUiCustomization(DEFAULT_UI_CUSTOMIZATION); - - console.log( - `Error fetching blueprint permissions : ${blueprintName} ${error}` - ); - }); - }, [blueprintName]); - const handleUpdateUi = (field, value) => { const newUiCustomization = { ...uiCustomization, [field]: value }; + const newUi = newUiCustomization.isCustomizationEnabled + ? newUiCustomization + : DEFAULT_UI_CUSTOMIZATION; if (field === "title" || field === "description" || field === "backgroundColor") { // Don't fade in for those fields @@ -197,44 +119,12 @@ export default function EditBlueprintUi({ blueprintName }) { // then the old preview is updated, and the preview on top fades out setOpacity(1); setTimeout(() => { - setOldUiCustomization(newUiCustomization); + setOldUiCustomization(newUi); setOpacity(0); }, 250); } - axios( - configApiCall( - api_path_blueprints + "?name=" + blueprintName, - "PUT", - { ...policyData, uiCustomization: JSON.stringify(newUiCustomization) }, - null - ) - ) - .then(() => { - setOpen(false); - setSeverity("success"); - setOpen(true); - setMessage( - i18next.t( - "updated_blueprint_permissions_successfully", - "Blueprint permissions successfully updated." - ) - ); - }) - .catch((error) => { - console.error(error); - setOpen(false); - setSeverity("error"); - setOpen(true); - setMessage( - i18next.t( - "error_updating_blueprint_permissions", - "Error occurred while updating blueprint permissions." - ) + - error + - "!" - ); - }); + updatePolicyData("uiCustomization", newUiCustomization); }; const handleImgDrop = (acceptedFiles, imgType) => { @@ -260,7 +150,6 @@ export default function EditBlueprintUi({ blueprintName }) { backgroundUrl: newUrl, backgroundColor: "", }); - setBgFile(acceptedFiles[0].name); handleUpdateUi("backgroundUrl", newUrl); } else if (imgType === "logo") { let newUrl = @@ -273,7 +162,6 @@ export default function EditBlueprintUi({ blueprintName }) { ...uiCustomization, logoUrl: newUrl, }); - setLogoFile(acceptedFiles[0].name); handleUpdateUi("logoUrl", newUrl); } }) @@ -282,34 +170,6 @@ export default function EditBlueprintUi({ blueprintName }) { }); }; - const handleDeleteLogo = (e) => { - setLogoFile(null); - setUiCustomization({ - ...uiCustomization, - customLogoImageUrl: null, - }); - e.stopPropagation(); - }; - - const handleDeleteBg = (e) => { - setBgFile(null); - setUiCustomization({ - ...uiCustomization, - customBackgroundImageUrl: null, - }); - e.preventDefault(); - e.stopPropagation(); - }; - - const handleColorChange = (color) => { - setUiCustomization({ - ...uiCustomization, - customBackgroundColor: color.hex, - customBackgroundImageUrl: null, - }); - setBgFile(null); - }; - return ( <div> <BlueprintSnackbar snackbar={snackbar} setSnackbar={setSnackbar} /> @@ -339,7 +199,7 @@ export default function EditBlueprintUi({ blueprintName }) { > <CustomUiPreview opacity={opacity} - uiCustomization={policyData.uiCustomization} + uiCustomization={uiCustomization} /> <CustomUiPreview isOldPreview @@ -349,16 +209,10 @@ export default function EditBlueprintUi({ blueprintName }) { </Grid> <Grid item xs={12} sm={12} md={12}> <EditBlueprintUiForm - uiCustomization={policyData.uiCustomization} + uiCustomization={uiCustomization} setUiCustomization={setUiCustomization} handleUpdateUi={handleUpdateUi} handleImgDrop={handleImgDrop} - setLogoFile={setLogoFile} - handleDeleteLogo={handleDeleteLogo} - bgFile={bgFile} - setBgFile={setBgFile} - handleDeleteBg={handleDeleteBg} - handleColorChange={handleColorChange} /> </Grid> </Grid> diff --git a/jams-react-client/src/views/Blueprint/PolicyDataContext.js b/jams-react-client/src/views/Blueprint/PolicyDataContext.js new file mode 100644 index 00000000..131db22a --- /dev/null +++ b/jams-react-client/src/views/Blueprint/PolicyDataContext.js @@ -0,0 +1,61 @@ +import React, { createContext, useEffect, useState } from "react"; + +import axios from "axios"; + +import configApiCall from "../../api"; +import { api_path_blueprints } from "../../globalUrls"; +import { parsePolicyData } from "./parsePolicyData"; +import { _updatePolicyData } from "./updatePolicyData"; +import { DEFAULT_POLICY_DATA } from "./policyData.constants"; + +export const PolicyDataContext = createContext(null); + +export const PolicyDataContextProvider = ({ blueprintName, children }) => { + const [policyData, setPolicyData] = useState(DEFAULT_POLICY_DATA); + const [snackbar, setSnackbar] = useState({ + open: false, + severity: "success", + message: "", + }); + + useEffect(() => { + axios( + configApiCall( + api_path_blueprints + "?name=" + blueprintName, + "GET", + null, + null + ) + ) + .then((response) => { + console.log("GET", response.data.policyData); + return parsePolicyData(response.data.policyData); + }) + .then((policyData) => { + console.log("PARSED", policyData); + setPolicyData(policyData); + }) + .catch((error) => { + console.log("Error fetching blueprint permissions : " + error); + }); + }, [blueprintName]); + + const updatePolicyData = (field, value) => { + _updatePolicyData( + blueprintName, + policyData, + setPolicyData, + field, + value, + setSnackbar + ); + }; + + return ( + <PolicyDataContext.Provider + value={{ policyData, updatePolicyData, snackbar, setSnackbar }} + > + {children} + </PolicyDataContext.Provider> + ); +}; diff --git a/jams-react-client/src/views/Blueprint/parsePolicyData.js b/jams-react-client/src/views/Blueprint/parsePolicyData.js new file mode 100644 index 00000000..f5da5f55 --- /dev/null +++ b/jams-react-client/src/views/Blueprint/parsePolicyData.js @@ -0,0 +1,101 @@ +import axios from "axios"; + +import configApiCall from "../../api"; +import { + api_path_get_ns_name_from_addr, + api_path_get_user_profile, +} from "../../globalUrls"; +import { DEFAULT_UI_CUSTOMIZATION } from "./policyData.constants"; + +const getModerators = async (defaultModerators) => { + const moderators = []; + const ids = defaultModerators.split("/").filter((id) => id !== ""); + + for (const id of ids) { + const usernameResponse = await axios( + configApiCall(api_path_get_ns_name_from_addr + id, "GET", null, null) + ); + const username = usernameResponse.data.name; + + const userProfileResponse = await axios( + configApiCall(api_path_get_user_profile + username, "GET", null, null) + ); + userProfileResponse.data["id"] = id; + moderators.push(userProfileResponse.data); + } + + return moderators; +}; + +const setConfigurationSettings = (policyData) => { + const { turnEnabled, proxyEnabled } = policyData; + + if (turnEnabled === true) { + policyData.selectedTurnOption = "customTurn"; + } else if (turnEnabled === false) { + policyData.selectedTurnOption = "disabledTurn"; + } else { + policyData.selectedTurnOption = "defaultTurn"; + } + delete policyData.turnEnabled; + + if (proxyEnabled === true) { + policyData.selectedDHTProxyOption = "customDHTProxy"; + } else if (proxyEnabled === false) { + policyData.selectedDHTProxyOption = "disabledDHTProxy"; + } else { + policyData.selectedDHTProxyOption = "defaultDHTProxy"; + } + delete policyData.proxyEnabled; + + return policyData; +}; + +const setCustomizationSettings = (policyData) => { + if (!policyData.uiCustomization) { + policyData.uiCustomization = DEFAULT_UI_CUSTOMIZATION; + return policyData; + } + + const result = JSON.parse(policyData.uiCustomization); + const ui = { isCustomizationEnabled: true }; + + ui.hasTitle = result.title !== ""; + ui.title = result.title; + ui.hasDescription = result.description !== ""; + ui.description = result.description; + ui.hasTips = result.hasTips; + + if (result.backgroundType === "default") { + ui.hasBackground = false; + } else if (result.backgroundType === "color") { + ui.hasBackground = true; + ui.backgroundColor = result.backgroundColorOrUrl; + } else if (result.backgroundType === "image") { + ui.hasBackground = true; + ui.backgroundUrl = result.backgroundColorOrUrl; + } + + // Get the name of the file from the url + ui.hasLogo = result.logoUrl !== ""; + if (ui.hasLogo) { + ui.logoUrl = result.logoUrl; + } + + policyData.uiCustomization = ui; + return policyData; +}; + +export const parsePolicyData = async (data) => { + let policyData = JSON.parse(data); + + policyData.blueprintModerators = await getModerators( + policyData.defaultModerators + ); + delete policyData.defaultModerators; + + policyData = setConfigurationSettings(policyData); + policyData = setCustomizationSettings(policyData); + + return policyData; +}; diff --git a/jams-react-client/src/views/Blueprint/policyData.constants.js b/jams-react-client/src/views/Blueprint/policyData.constants.js new file mode 100644 index 00000000..967baebb --- /dev/null +++ b/jams-react-client/src/views/Blueprint/policyData.constants.js @@ -0,0 +1,39 @@ +export const DEFAULT_UI_CUSTOMIZATION = { + isCustomizationEnabled: false, + hasTitle: true, + title: "", + hasDescription: true, + description: "", + hasTips: false, + + hasBackground: false, + backgroundColor: "", + backgroundUrl: "", + + hasLogo: true, + logoUrl: "", +}; + +export const DEFAULT_POLICY_DATA = { + videoEnabled: true, + publicInCalls: false, + autoAnswer: false, + peerDiscovery: true, + allowLookup: true, + + rendezVous: false, + blueprintModerators: [], + + upnpEnabled: true, + + selectedTurnOption: "defaultTurn", + turnServer: "turn.jami.net", + turnServerUserName: "ring", + turnServerPassword: "ring", + + selectedDHTProxyOption: "defaultDHTProxy", + proxyServer: "dhtproxy.jami.net", + dhtProxyListUrl: "", + + uiCustomization: DEFAULT_UI_CUSTOMIZATION, +}; diff --git a/jams-react-client/src/views/Blueprint/updatePolicyData.js b/jams-react-client/src/views/Blueprint/updatePolicyData.js new file mode 100644 index 00000000..d5eafb0f --- /dev/null +++ b/jams-react-client/src/views/Blueprint/updatePolicyData.js @@ -0,0 +1,168 @@ +import axios from "axios"; +import i18next from "i18next"; + +import configApiCall from "api"; +import { api_path_blueprints } from "globalUrls"; +import { debounce } from "lodash"; + +const updatePerms = (data, field, value) => { + data.defaultModerators = data.blueprintModerators + .map((moderator) => moderator.id) + .join("/"); + delete data.blueprintModerators; + + if (field === "peerDiscovery") { + data.accountDiscovery = value; + data.accountPublish = value; + } + + return data; +}; + +const updateConfig = (data) => { + const { selectedTurnOption, selectedDHTProxyOption } = data; + // if undefined, it means we want the default values + if (selectedTurnOption !== "customTurn") { + delete data.turnServer; + delete data.turnServerUserName; + delete data.turnServerPassword; + } + + if (selectedDHTProxyOption !== "customDHTProxy") { + delete data.proxyServer; + delete data.dhtProxyListUrl; + } + + if (selectedTurnOption === "customTurn") { + data.turnEnabled = true; + } else if (selectedTurnOption === "disabledTurn") { + data.turnEnabled = false; + } + delete data.selectedTurnOption; + + if (selectedDHTProxyOption === "customDHTProxy") { + data.proxyEnabled = true; + } else if (selectedDHTProxyOption === "disabledDHTProxy") { + data.proxyEnabled = false; + } + delete data.selectedDHTProxyOption; + + return data; +}; + +const updateUiCustomization = (data) => { + if (data.uiCustomization.isCustomizationEnabled === false) { + return data; + } + + const { + hasTitle, + title, + hasDescription, + description, + hasTips, + + hasBackground, + backgroundColor, + backgroundUrl, + + hasLogo, + logoUrl, + } = data.uiCustomization; + const ui = {}; + + if (hasTitle === false) { + ui.title = ""; + } else if (title !== "") { + ui.title = title; + } + + if (hasDescription === false) { + ui.description = ""; + } else if (description !== "") { + ui.description = description; + } + + ui.areTipsEnabled = hasTips; + + if (hasBackground === false) { + ui.backgroundType = "default"; + } else if (backgroundUrl !== "") { + ui.backgroundType = "image"; + ui.backgroundColorOrUrl = backgroundUrl; + } else if (backgroundColor !== "") { + ui.backgroundType = "color"; + ui.backgroundColorOrUrl = backgroundColor; + } else { + ui.backgroundType = "default"; + } + + if (hasLogo === false) { + ui.logoUrl = ""; + } else if (logoUrl !== "") { + ui.logoUrl = logoUrl; + } + + console.log("updateUiCustomization", ui); + data.uiCustomization = JSON.stringify(ui); + return data; +}; + +const sendPutRequest = (blueprintName, data, setSnackbar) => { + console.log("PUT", data); + + axios( + configApiCall( + api_path_blueprints + "?name=" + blueprintName, + "PUT", + data, + null + ) + ) + .then((response) => { + const message = i18next.t( + "updated_blueprint_permissions_successfully", + "Blueprint permissions successfully updated." + ); + setSnackbar({ + open: true, + severity: "success", + message, + }); + }) + .catch((error) => { + const msg = i18next.t( + "error_updating_blueprint_permissions", + "Error occurred while updating blueprint permissions." + ); + setSnackbar({ + open: true, + severity: "error", + message: `${msg} ${error}!`, + }); + }); +}; + +const debouncedSendPutRequest = debounce(sendPutRequest, 200, { + trailing: true, +}); + +export const _updatePolicyData = ( + blueprintName, + policyData, + setPolicyData, + field, + value, + setSnackbar +) => { + setPolicyData((state) => ({ ...state, [field]: value })); + + let data = { ...policyData, [field]: value }; + data = updatePerms(data, field, value); + data = updateConfig(data); + data = updateUiCustomization(data); + + console.log("updatePolicyData", { field, value }); + + debouncedSendPutRequest(blueprintName, data, setSnackbar); +}; -- GitLab