diff --git a/webui/src/App.js b/webui/src/App.js index bf7c026..9d8d242 100755 --- a/webui/src/App.js +++ b/webui/src/App.js @@ -5,18 +5,12 @@ import LoginForm from "./Components/Forms/LoginForm"; import {Container} from "reactstrap"; import {BrowserRouter} from "react-router-dom"; import {Route} from "react-router"; -import {setGlobal} from "reactn"; import useAuth from "./Hooks/auth"; import IndexPage from "./Components/Pages/IndexPage"; import GroupPage from "./Components/Pages/GroupPage"; import Loading from "./Components/Loading"; import LightPage from "./Components/Pages/LightPage"; -setGlobal({ - "auth/login": false, - "auth/checked": false, -}); - export default function App() { const [hasStarted, setHasStarted] = useState(false); const {isLoggedIn, isChecked, verify} = useAuth(); diff --git a/webui/src/Components/Group.jsx b/webui/src/Components/Group.jsx index a080833..554b0a0 100644 --- a/webui/src/Components/Group.jsx +++ b/webui/src/Components/Group.jsx @@ -6,10 +6,15 @@ import Loading from "./Loading"; import {deleteGroup} from "../Helpers/groups"; import ColorModal from "./Modals/ColorModal"; import {changeColor} from "../Helpers/lights"; +import GroupPropertiesModal from "./Modals/GroupPropertiesModal"; +import useAuth from "../Hooks/auth"; -function Group({id, name}) { +function Group({id, name, permissions}) { + const {user} = useAuth(); const lights = useLights({groupId: id}); - const [colorModal, setColorModal] = useState(""); + + const [colorModal, setColorModal] = useState(false); + const [propModal, setPropModal] = useState(false); const ready = lights !== null; const noLights = ready && lights.length === 0; @@ -34,6 +39,14 @@ function Group({id, name}) { pValue = lights[0].on; } + function iCan(name) { + const perm = permissions.find(p => p.userId === user.id); + + return typeof perm !== "undefined" + ? perm[name] + : false; + } + return ( {name} @@ -42,15 +55,21 @@ function Group({id, name}) { ? {lights.map(light => )} : } - - + {(iCan("manage") || iCan("write") || iCan("delete")) && ( + + {iCan("manage") && ( + + )} {" "} - {hasLights && ( + {hasLights && iCan("write") && ( )} {" "} - {id > 0 && } - + {iCan("delete") && (id > 0) && ( + + )} + + )} {colorModal && ( setColorModal(false)} /> )} + {propModal && ( + setPropModal(false)} + /> + )} ); } diff --git a/webui/src/Components/Modals/GroupAddModal.jsx b/webui/src/Components/Modals/GroupAddModal.jsx index dffcd93..d2c5d26 100644 --- a/webui/src/Components/Modals/GroupAddModal.jsx +++ b/webui/src/Components/Modals/GroupAddModal.jsx @@ -1,5 +1,5 @@ import React, {useState} from "react"; -import {Button, Form, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; +import {Button, Col, Form, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; import {addGroup} from "../../Helpers/groups"; function GroupAddModal({onClose}) { @@ -10,15 +10,17 @@ function GroupAddModal({onClose}) { Ny gruppe
- -
diff --git a/webui/src/Components/Modals/GroupPropertiesModal.jsx b/webui/src/Components/Modals/GroupPropertiesModal.jsx new file mode 100644 index 0000000..eabfea6 --- /dev/null +++ b/webui/src/Components/Modals/GroupPropertiesModal.jsx @@ -0,0 +1,101 @@ +import React, {useState} from "react"; +import useAuth from "../../Hooks/auth"; +import { + Button, + Col, + Form, + FormGroup, + Input, + InputGroup, + InputGroupAddon, + Label, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + Row +} from "reactstrap"; +import PermissionsModal from "./PermissionsModal"; + +function GroupPropertiesModal({id, nValue, permissions, onClose}) { + const {users} = useAuth(); + const [name, setName] = useState(nValue); + const [permUserId, setPermUserId] = useState(null); + const [permModal, setPermModal] = useState(false); + + function permissionFor(userId) { + const perm = permissions.find(p => p.userId === userId); + + return typeof perm !== "undefined" + ? perm + : null; + } + + return ( + + Endre gruppe + +
+ + + + setName(e.target.value)}/> + + + + + + {users.map(user => { + const permission = permissionFor(user.id); + const btnColor = permission !== null ? "secondary" : "success"; + const btnLabel = permission !== null ? "Endre" : "Opprett"; + + return ( + + + + + + + + + ) + })} + + +
+
+ + + {" "} + + + {permModal && ( + setPermModal(false)} + /> + )} +
+ ); +} + +export default GroupPropertiesModal; diff --git a/webui/src/Components/Modals/LightPropertiesModal.jsx b/webui/src/Components/Modals/LightPropertiesModal.jsx index 0b0700a..27594a3 100644 --- a/webui/src/Components/Modals/LightPropertiesModal.jsx +++ b/webui/src/Components/Modals/LightPropertiesModal.jsx @@ -1,6 +1,5 @@ import React, {useState} from "react"; -import {Button, Form, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; -import {addGroup} from "../../Helpers/groups"; +import {Button, Col, Form, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; import useGroups from "../../Hooks/group"; import Loading from "../Loading"; import {changeLight} from "../../Helpers/lights"; @@ -18,27 +17,31 @@ function LightPropertiesModal({id, gValue, nValue, onClose}) { Lysegenskaper
- -
diff --git a/webui/src/Components/Modals/PermissionsModal.jsx b/webui/src/Components/Modals/PermissionsModal.jsx new file mode 100644 index 0000000..ffc73ee --- /dev/null +++ b/webui/src/Components/Modals/PermissionsModal.jsx @@ -0,0 +1,84 @@ +import React, {useState} from "react"; +import {Button, CustomInput, FormGroup, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; +import {savePermissions} from "../../Helpers/groups"; + +function PermissionsModal({groupId, userId, permissions, onClose}) { + function getPermission(type) { + if (permissions === null || typeof permissions[type] === "undefined") { + return false; + } + + return permissions[type]; + } + + const [read, setRead] = useState(getPermission("read")); + const [write, setWrite] = useState(getPermission("write")); + const [create, setCreate] = useState(getPermission("create")); + const [remove, setRemove] = useState(getPermission("delete")); + const manage = getPermission("manage"); + + return ( + + Endre gruppe + + + setRead(e.target.checked)}/> + + + setWrite(e.target.checked)}/> + + + setCreate(e.target.checked)}/> + + + setRemove(e.target.checked)}/> + + + + + + + + {" "} + + + + ); +} + +export default PermissionsModal; diff --git a/webui/src/Helpers/groups.js b/webui/src/Helpers/groups.js index f84ed12..088ee53 100644 --- a/webui/src/Helpers/groups.js +++ b/webui/src/Helpers/groups.js @@ -1,6 +1,6 @@ import {randId} from "./random"; -import {fetchDelete, fetchGet, fetchPost} from "./fetcher"; -import {notNullish, nullish} from "./null"; +import {fetchDelete, fetchGet, fetchPatch, fetchPost} from "./fetcher"; +import {nullish} from "./null"; const localData = {}; const callbacks = []; @@ -42,6 +42,14 @@ export function deleteGroup(groupId) { }); } +export function savePermissions(groupId, userId, permissions) { + fetchPatch(`/group/${groupId}/permission/${userId}`, permissions).then(({data, error}) => { + if (error === null) { + fetchAll(); + } + }); +} + function fetchAll() { fetchGet("/group/").then(({data, error}) => { if (error === null) { diff --git a/webui/src/Hooks/auth.js b/webui/src/Hooks/auth.js index 3f2de6a..f9b18d8 100644 --- a/webui/src/Hooks/auth.js +++ b/webui/src/Hooks/auth.js @@ -1,15 +1,40 @@ -import {useGlobal} from "reactn"; +import {setGlobal, useGlobal} from "reactn"; import {fetchGet, fetchPost} from "../Helpers/fetcher"; +setGlobal({ + "auth/login": false, + "auth/checked": false, + "auth/users/me": null, + "auth/users/all": [], +}); + export default function useAuth() { const [isLoggedIn, setIsLoggedIn] = useGlobal("auth/login"); const [isChecked, setIsChecked] = useGlobal("auth/checked"); + const [user, setUser] = useGlobal("auth/users/me"); + const [users, setUsers] = useGlobal("auth/users/all"); + + function fetchUsers() { + fetchGet("/user/").then(({data, error}) => { + if (error === null) { + setUsers(data); + } + }); + } function verify() { setIsChecked(false); fetchGet("/user/session").then(({data, error}) => { - setIsLoggedIn(error === null && data.loggedIn); + const validSession = error === null && data.loggedIn; + + setIsLoggedIn(validSession); + + if (validSession) { + setUser(data.user); + fetchUsers(); + } + setIsChecked(true); }) } @@ -26,6 +51,8 @@ export default function useAuth() { } setIsLoggedIn(true); + setIsLoggedIn(data); + fetchUsers(); }); } @@ -60,5 +87,5 @@ export default function useAuth() { }) } - return {isLoggedIn, isChecked, verify, login, logout, register}; + return {isLoggedIn, isChecked, user, users, verify, login, logout, register}; }