From 036e4d344899ba37e8612d1c4ff69b4c61a35034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yland?= <daniehoy@stud.ntnu.no> Date: Wed, 24 Apr 2024 16:57:20 +0200 Subject: [PATCH] Fixed up sysAdmin functionality --- Backend/API/handlers/newDepartment.go | 11 +-- Backend/API/handlers/newGateway.go | 63 +++++++++++- Backend/API/other/sqlqueries.go | 12 ++- .../src/components/manageBuildDep.tsx | 77 ++++++++++++--- .../src/components/manageGateway.tsx | 97 +++++++++++++------ .../src/components/manageProcesses.tsx | 35 +++++-- 6 files changed, 230 insertions(+), 65 deletions(-) diff --git a/Backend/API/handlers/newDepartment.go b/Backend/API/handlers/newDepartment.go index b438e91..133db26 100644 --- a/Backend/API/handlers/newDepartment.go +++ b/Backend/API/handlers/newDepartment.go @@ -101,15 +101,8 @@ func NewDepartment(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) return } - //get the building id - building, err := other.GetBuildingIdByName(data.BuildingName, CompID) - if err != nil { - log.Println(err.Error()) - w.WriteHeader(http.StatusBadRequest) - return - } - depId, err := other.GetDepartmentIdByName(data.DepartmentName1, building) + depId, err := other.GetDepartmentIdByName(data.DepartmentName1, CompID) if err != nil { log.Println(err.Error()) w.WriteHeader(http.StatusBadRequest) @@ -167,6 +160,7 @@ func NewDepartment(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) return } + //get the building id depId, err := other.GetDepartmentIdByName(data.DepartmentName, CompID) if err != nil { @@ -174,6 +168,7 @@ func NewDepartment(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) return } + //calls function to add building err = other.DeleteDepartment(depId) if err != nil { diff --git a/Backend/API/handlers/newGateway.go b/Backend/API/handlers/newGateway.go index b920cc4..5a16b13 100644 --- a/Backend/API/handlers/newGateway.go +++ b/Backend/API/handlers/newGateway.go @@ -11,7 +11,7 @@ import ( func AddGateway(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Headers", "Content-Type") w.Header().Set("Access-Control-Allow-Origin", ""+other.WebsiteURL) - w.Header().Set("Access-Control-Allow-Methods", "POST, DELETE, OPTIONS") + w.Header().Set("Access-Control-Allow-Methods", "POST, DELETE, PUT, OPTIONS") if r.Method == http.MethodPost { decoder := json.NewDecoder(r.Body) //creates an anonymous struct to reduce clutter in structs file @@ -49,6 +49,60 @@ func AddGateway(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) return } + } else if r.Method == http.MethodPut { + decoder := json.NewDecoder(r.Body) + //creates an anonymous struct to reduce clutter in structs file + data := struct { + Name string `json:"name"` + OldName string `json:"oldName"` + Eui string `json:"eui"` + OldEui string `json:"oldEui"` + Token string `json:"sessionToken"` + }{} + err := decoder.Decode(&data) + if err != nil { + println(err.Error()) + return + } + valid, err := other.IsTokenStillActive(data.Token) + if !valid { + log.Println("Session token expired or not valid!") + w.WriteHeader(http.StatusUnauthorized) + if err != nil { + log.Println(err.Error()) + } + return + } + //verify that the user making the request is allowed + permissionLevel, err := other.GetPermissionFromToken(data.Token) + if err != nil { + log.Println(err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } + if permissionLevel != 0 { + w.WriteHeader(http.StatusUnauthorized) + return + } + UserID, err := other.GetUserIDFromToken(data.Token) + if err != nil { + log.Println(err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } + CompID, err := other.GetCompanyFromUserID(UserID) + if err != nil { + log.Println(err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } + //calls function to edit building + err = other.EditGateway(data.Eui, data.OldEui, data.Name, data.OldName, CompID) + if err != nil { + println(err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } } else if r.Method == http.MethodDelete { decoder := json.NewDecoder(r.Body) //creates an anonymous struct to reduce clutter in structs file @@ -71,20 +125,19 @@ func AddGateway(w http.ResponseWriter, r *http.Request) { } return } - - err = other.DeleteGateway(data.Eui) + err = other.DoNewRequest(nil, other.CHIRP_URL+"api/gateways/"+data.Eui, http.MethodDelete) if err != nil { log.Println(err.Error()) w.WriteHeader(http.StatusInternalServerError) return } - - err = other.DoNewRequest(nil, other.CHIRP_URL+"api/gateways/"+data.Eui, http.MethodDelete) + err = other.DeleteGateway(data.Eui) if err != nil { log.Println(err.Error()) w.WriteHeader(http.StatusInternalServerError) return } + } else if r.Method == http.MethodOptions { } else { diff --git a/Backend/API/other/sqlqueries.go b/Backend/API/other/sqlqueries.go index cfc8265..87575ea 100644 --- a/Backend/API/other/sqlqueries.go +++ b/Backend/API/other/sqlqueries.go @@ -134,6 +134,10 @@ func DeleteBuilding(id int) error { if err != nil { return err } + _, err = DB.Exec("DELETE FROM sensorData WHERE eui=?", eui) + if err != nil { + return err + } } _, err = DB.Exec("DELETE FROM machine WHERE building_id=?", id) @@ -193,9 +197,9 @@ func DeleteDepartment(id int) error { return nil } -func GetDepartmentIdByName(name string, buildId int) (int, error) { +func GetDepartmentIdByName(name string, compId int) (int, error) { var id = 0 - row := DB.QueryRow("SELECT id FROM department WHERE name=? AND building_id=?", name, buildId) + row := DB.QueryRow("SELECT id FROM department WHERE name=? AND building_id IN (SELECT id FROM building WHERE company_id=?)", name, compId) err := row.Scan(&id) if err != nil { return 0, err @@ -478,8 +482,8 @@ func AddGateway(token string, eui string, name string) error { } return nil } -func EditGateway(newEui string, oldEui string) error { - _, err := DB.Exec("UPDATE gateway SET eui=? where eui=?", newEui, oldEui) +func EditGateway(newEui string, oldEui string, newName string, oldName string, compId int) error { + _, err := DB.Exec("UPDATE gateway SET eui=?, name=? where eui=? AND name=? AND company_id=?", newEui, newName, oldEui, oldName, compId) if err != nil { return err } diff --git a/Frontend/power-tracker/src/components/manageBuildDep.tsx b/Frontend/power-tracker/src/components/manageBuildDep.tsx index e6ef052..b46872d 100644 --- a/Frontend/power-tracker/src/components/manageBuildDep.tsx +++ b/Frontend/power-tracker/src/components/manageBuildDep.tsx @@ -206,8 +206,30 @@ function BuildDepSubpage () { </AccordionTrigger> <Separator orientation='vertical' className="mx-[5px]"/> <div className="h-[100%] flex items-center justify-around"> - <Button className="h-[30px] w-[60px]" variant="outline">Edit</Button> - <Button className="h-[30px] w-[60px]" variant="outline">Delete</Button> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" onClick={()=>{setBuildingNameInput(buildDep.building.name)}}>Edit</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Edit {buildDep.building.name}</AlertDialogHeader> + <form onSubmit={(e)=>{e.preventDefault();editBuilding(buildDep.building.name, buildingNameInput); setBuildingNameInput("")}}> + <Input className="mb-[20px]" type="text" placeholder="Buidling Name" value={buildingNameInput} onChange={(event) => setBuildingNameInput(event.target.value)} required/> + <AlertDialogAction type='submit'>Confirm</AlertDialogAction> + <AlertDialogCancel onClick={()=>{setBuildingNameInput("")}}>Cancel</AlertDialogCancel> + </form> + </AlertDialogContent> + </AlertDialog> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" >Delete</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Are you sure about deleting {buildDep.building.name} and all its machines and departments?</AlertDialogHeader> + <AlertDialogAction onClick={()=>deleteBuilding(buildDep.building.name)}>DELETE</AlertDialogAction> + <AlertDialogCancel>Cancel</AlertDialogCancel> + </AlertDialogContent> + </AlertDialog> + </div> <Separator orientation='vertical' className="ml-[5px]"/> </div> @@ -228,8 +250,17 @@ function BuildDepSubpage () { <Plus className="h-[18px]" /> </Button> </AlertDialogTrigger> - <AlertDialogContent> {/* NEEDS FUNCTIONALITY */} - <form> + <AlertDialogContent> + <form onSubmit={(e) => { + e.preventDefault(); + console.log(departmentNameInput) + if (departmentNameInput !== "") { + addDepartment(buildDep.building.name, departmentNameInput); + setDepartmentNameInput(""); + setBuildingNameInputDP(""); + setDepartmentBool(!departmentBool); + } + }}> <AlertDialogHeader> <h4 className="scroll-m-20 text-xl font-semibold tracking-tight"> Add Department to: {buildDep.building.name} @@ -237,7 +268,7 @@ function BuildDepSubpage () { </AlertDialogHeader> <div className="flex items-center space-x-2"> <Label htmlFor='addDepName'>Name</Label> - <Input id="addDepName" className="my-[20px] w-[200px]" required/> + <Input id="addDepName" className="my-[20px] w-[200px]" required value={departmentNameInput} onChange={(event) => setDepartmentNameInput(event.target.value)}/> </div> <AlertDialogFooter> <AlertDialogAction> @@ -284,8 +315,29 @@ function BuildDepSubpage () { </div> <div/> <div className="h-[100%] flex items-center justify-around"> - <Button className="h-[30px] w-[60px]" variant="outline">Edit</Button> - <Button className="h-[30px] w-[60px]" variant="outline">Delete</Button> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" onClick={()=>{setDepartmentNameInput(department.name)}}>Edit</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Edit {department.name}</AlertDialogHeader> + <form onSubmit={(e)=>{e.preventDefault();editDepartment(department.name, departmentNameInput,buildDep.building.name);setDepartmentNameInput("")}}> + <Input className="mb-[20px]" type="text" placeholder="Buidling Name" value={departmentNameInput} onChange={(event) => setDepartmentNameInput(event.target.value)} required/> + <AlertDialogAction type='submit'>Confirm</AlertDialogAction> + <AlertDialogCancel onClick={()=>{setDepartmentNameInput("")}}>Cancel</AlertDialogCancel> + </form> + </AlertDialogContent> + </AlertDialog> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" >Delete</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Are you sure about deleting {department.name}? This will remove it from alle machines that has this department.</AlertDialogHeader> + <AlertDialogAction onClick={()=>deleteDepartment(department.name)}>DELETE</AlertDialogAction> + <AlertDialogCancel>Cancel</AlertDialogCancel> + </AlertDialogContent> + </AlertDialog> </div> <Separator orientation='vertical' className="mx-[5px]"/> <div></div> @@ -373,8 +425,7 @@ const addBuilding = (e: React.FormEvent<HTMLFormElement>, buildingName: string) }) } -const addDepartment = (e: React.FormEvent<HTMLFormElement>, buildingName: string, departmentName: string) => { - e.preventDefault() +const addDepartment = ( buildingName: string, departmentName: string) => { var token: string = "" var tokenBool = sessionStorage.getItem("TOKEN") @@ -449,8 +500,8 @@ const editDepartment= ( oldDepartmentName: string, newDepartmentName: string, bu }) } -const deleteBuilding = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, name: string) => { - e.preventDefault() +const deleteBuilding = ( name: string) => { + var token: string = "" var tokenBool = sessionStorage.getItem("TOKEN") @@ -474,8 +525,8 @@ const deleteBuilding = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, name console.log(error) }) } -const deleteDepartment= (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, name: string) => { - e.preventDefault() +const deleteDepartment= ( name: string) => { + var token: string = "" var tokenBool = sessionStorage.getItem("TOKEN") diff --git a/Frontend/power-tracker/src/components/manageGateway.tsx b/Frontend/power-tracker/src/components/manageGateway.tsx index d4328ad..41f9e62 100644 --- a/Frontend/power-tracker/src/components/manageGateway.tsx +++ b/Frontend/power-tracker/src/components/manageGateway.tsx @@ -60,7 +60,7 @@ function ManageGateways() { return ( <ResizablePanelGroup className='flex h-[100%]' direction="horizontal"> - <ResizablePanel minSize={51}> + <ResizablePanel minSize={72.5}> {/* Title and search bar */} <div className="w-[100%] h-[40px] flex justify-between content-center"> <h1 className="scroll-m-20 text-2xl font-semibold tracking-tight">Buildings and Departments</h1> @@ -84,29 +84,18 @@ function ManageGateways() { </Button> </AlertDialogTrigger> <AlertDialogContent> - <form onSubmit={(e) => {addGateway(e, euiInput, nameInput); setEuiInput(""); setNameInput("");}}> - <p>EUI</p> - <Input type="text" id="uname" value={euiInput} onChange={(event) => setEuiInput(event.target.value)} required/> - <p>Name</p> - <Input type="text" id="name" value={nameInput} onChange={(event) => setNameInput(event.target.value)} required/> + <AlertDialogHeader><strong>Add Gateway:</strong></AlertDialogHeader> + <form onSubmit={(e) => {addGateway(euiInput, nameInput); setEuiInput(""); setNameInput(""); e.preventDefault()}}> + <label>EUI</label> + <Input className="mb-[20px]" type="text" value={euiInput} onChange={(event) => setEuiInput(event.target.value)} required/> + <label>Name</label> + <Input className="mb-[20px]" type="text" value={nameInput} onChange={(event) => setNameInput(event.target.value)} required/> <br/> <br/> - </form> - <AlertDialogFooter> + <AlertDialogFooter> + <AlertDialogAction type='submit'>Submit gateway!</AlertDialogAction> <AlertDialogCancel>Cancel</AlertDialogCancel> - <AlertDialogAction type='submit' onClick={() => { - setGatewayData(prevState => ({ - ...prevState, - gateway: [ - ...prevState.gateway, - { - eui_gate: euiInput, - name: nameInput - } - ] - })); - }}>Submit gateway! - </AlertDialogAction> </AlertDialogFooter> + </form> </AlertDialogContent> </AlertDialog> @@ -129,8 +118,32 @@ function ManageGateways() { </TableCell> <TableCell className="w-[400px]">{gates.eui_gate}</TableCell> <TableCell className="w-[1fr] flex justify-end"> - <Button className="h-[30px] w-[60px] mr-[5px]" variant="outline">Edit</Button> - <Button className="h-[30px] w-[60px]" variant="outline">Delete</Button> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" onClick={()=>{setEuiInput(gates.eui_gate); setNameInput(gates.name)}}>Edit</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Edit {gates.eui_gate} - {gates.name}</AlertDialogHeader> + <form onSubmit={(e)=>{e.preventDefault();editGateway(euiInput,gates.eui_gate, nameInput, gates.name); setEuiInput(""); setNameInput("");}}> + <label>EUI</label> + <Input className="mb-[20px]" type="text" placeholder="EUI" value={euiInput} onChange={(event) => setEuiInput(event.target.value)} required/> + <label>Name</label> + <Input className="mb-[20px]" type="text" placeholder="Name" value={nameInput} onChange={(event) => setNameInput(event.target.value)} required/> + <AlertDialogAction type='submit'>Confirm</AlertDialogAction> + <AlertDialogCancel onClick={()=>{setEuiInput(""); setNameInput("");}}>Cancel</AlertDialogCancel> + </form> + </AlertDialogContent> + </AlertDialog> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" >Delete</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Are you sure about deleting {gates.eui_gate} - {gates.name}?</AlertDialogHeader> + <AlertDialogAction onClick={()=>deleteGateway(gates.eui_gate)}>DELETE</AlertDialogAction> + <AlertDialogCancel>Cancel</AlertDialogCancel> + </AlertDialogContent> + </AlertDialog> </TableCell> </TableRow> ))} @@ -141,7 +154,7 @@ function ManageGateways() { <ResizableHandle withHandle className="mx-[10px]" /> - <ResizablePanel defaultSize={75} className="w-[400px]"> + <ResizablePanel defaultSize={72.5} className="w-[400px]"> </ResizablePanel> </ResizablePanelGroup> @@ -149,9 +162,8 @@ function ManageGateways() { } -const addGateway = (e: React.FormEvent<HTMLFormElement>, euiI: string, nameI: string) => { - e.preventDefault() - +const addGateway = ( euiI: string, nameI: string) => { + var token: string = "" var tokenBool = sessionStorage.getItem("TOKEN") if (tokenBool == null) { @@ -174,8 +186,35 @@ const addGateway = (e: React.FormEvent<HTMLFormElement>, euiI: string, nameI: st }) } -const deleteProcess = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, eui: string) => { - e.preventDefault() +const editGateway= ( eui: string, oldEui: string, name: string, oldName: string) => { + + + var token: string = "" + var tokenBool = sessionStorage.getItem("TOKEN") + if (tokenBool == null) { + redirect('/') + } else { + token = tokenBool + } + console.log('URL To call: ' + IngressAPI + 'token used' + token) + axios.put( + IngressAPI + '/add-gateway', + { + name: name, + oldName: oldName, + eui: eui, + oldEui: oldEui, + sessionToken: token, + }) + .then((res)=>{ + console.log(res.data) + }).catch((error) => { + console.log(error) + }) +} + +const deleteGateway = ( eui: string) => { + var token: string = "" var tokenBool = sessionStorage.getItem("TOKEN") if (tokenBool == null) { diff --git a/Frontend/power-tracker/src/components/manageProcesses.tsx b/Frontend/power-tracker/src/components/manageProcesses.tsx index 8db2204..7352d50 100644 --- a/Frontend/power-tracker/src/components/manageProcesses.tsx +++ b/Frontend/power-tracker/src/components/manageProcesses.tsx @@ -183,12 +183,36 @@ const ManageProcesses= () => { <Separator orientation='vertical' className="mr-[5px]"/> <div className='flex flex-row'> <Waypoints className="mx-[20px] mt-[2px]" /> - <h4 className="scroll-m-20 text-xl font-semibold tracking-tight">{process.name}</h4> + <strong><h4 className="scroll-m-20 text-xl font-semibold tracking-tight">{process.name}</h4></strong> </div> <Separator orientation='vertical' className="mx-[5px]"/> <div className="h-[100%] flex items-center justify-around"> - <Button className="h-[30px] w-[60px]" variant="outline">Edit</Button> - <Button className="h-[30px] w-[60px]" variant="outline">Delete</Button> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" onClick={()=>{setText(process.name); setDesc(process.description)}}>Edit</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Edit {process.name}</AlertDialogHeader> + <form onSubmit={(e)=>{e.preventDefault();editProcess(process.name, text ,process.description,desc); setText(""); setDesc("");}}> + <label>Process Name</label> + <Input className="mb-[20px]" type="text" placeholder="Process Name" value={text} onChange={(event) => setText(event.target.value)} required/> + <label>Description</label> + <Input className="mb-[20px]" type="text" placeholder="Description" value={desc} onChange={(event) => setDesc(event.target.value)} required/> + <AlertDialogAction type='submit'>Confirm</AlertDialogAction> + <AlertDialogCancel onClick={()=>{setText(""); setDesc("");}}>Cancel</AlertDialogCancel> + </form> + </AlertDialogContent> + </AlertDialog> + <AlertDialog> + <AlertDialogTrigger asChild> + <Button className="h-[30px] w-[60px]" variant="outline" >Delete</Button> + </AlertDialogTrigger> + <AlertDialogContent> + <AlertDialogHeader>Are you sure about deleting {process.name}?</AlertDialogHeader> + <AlertDialogAction onClick={()=>deleteProcess(process.name, process.description)}>DELETE</AlertDialogAction> + <AlertDialogCancel>Cancel</AlertDialogCancel> + </AlertDialogContent> + </AlertDialog> </div> <Separator orientation='vertical' className="ml-[5px]"/> </div> @@ -430,8 +454,8 @@ const editProcess = ( oldName: string, newName: string, oldDescription: string, console.log(error) }) } -const deleteProcess = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, name: string, description:string) => { - e.preventDefault() +const deleteProcess = (name: string, description:string) => { + var token: string = "" var tokenBool = sessionStorage.getItem("TOKEN") @@ -482,7 +506,6 @@ async function fetchDataProcess(): Promise<Processes[]> { }).catch((error) => { console.log(error) }) - console.log(processArrray) return processArrray } -- GitLab