From 531e9a0535b873188219bff887824e8f08b2d2b1 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 17:38:45 +0100 Subject: [PATCH 01/63] Fix links in UserProjectPage component --- frontend/src/Pages/UserPages/UserProjectPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/Pages/UserPages/UserProjectPage.tsx b/frontend/src/Pages/UserPages/UserProjectPage.tsx index 4760217..eab866b 100644 --- a/frontend/src/Pages/UserPages/UserProjectPage.tsx +++ b/frontend/src/Pages/UserPages/UserProjectPage.tsx @@ -7,12 +7,12 @@ function UserProjectPage(): JSX.Element { <>

{useLocation().state}

- +

Your Time Reports

- +

New Time Report

From 83e781c877f40a617cfe5a54159758f752157660 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Mon, 18 Mar 2024 18:31:58 +0100 Subject: [PATCH 02/63] Fixed getting the username and removed comment --- frontend/src/Components/UserProjectListAdmin.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/Components/UserProjectListAdmin.tsx b/frontend/src/Components/UserProjectListAdmin.tsx index 423e793..c4857db 100644 --- a/frontend/src/Components/UserProjectListAdmin.tsx +++ b/frontend/src/Components/UserProjectListAdmin.tsx @@ -9,7 +9,7 @@ const UserProjectListAdmin: React.FC = () => { const fetchProjects = async (): Promise => { try { const token = localStorage.getItem("accessToken") ?? ""; - const username = getUsernameFromContext(); // Assuming you have a function to get the username from your context + const username = localStorage.getItem("username") ?? ""; const response = await api.getUserProjects(username, token); if (response.success) { @@ -32,7 +32,6 @@ const UserProjectListAdmin: React.FC = () => { {projects.map((project) => (
  • {project.name} - {/* Add any additional project details you want to display */}
  • ))} From a2ad2913e4a65e45cd91f69a155898d4127ec7d4 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 19:34:15 +0100 Subject: [PATCH 03/63] Add NotFoundPage component --- frontend/src/Pages/NotFoundPage.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 frontend/src/Pages/NotFoundPage.tsx diff --git a/frontend/src/Pages/NotFoundPage.tsx b/frontend/src/Pages/NotFoundPage.tsx new file mode 100644 index 0000000..cae9861 --- /dev/null +++ b/frontend/src/Pages/NotFoundPage.tsx @@ -0,0 +1,18 @@ +import Button from "../Components/Button"; + +export default function NotFoundPage(): JSX.Element { + return ( + + ); +} From 3e9dc87100eed22a6ba1382727cc8041d7c3d6d5 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 19:36:28 +0100 Subject: [PATCH 04/63] Add NotFoundPage to handle 404 errors --- frontend/src/main.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 193b692..a1e466e 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -29,12 +29,14 @@ import AdminProjectManageMembers from "./Pages/AdminPages/AdminProjectManageMemb import AdminProjectStatistics from "./Pages/AdminPages/AdminProjectStatistics.tsx"; import AdminProjectViewMemberInfo from "./Pages/AdminPages/AdminProjectViewMemberInfo.tsx"; import AdminProjectPage from "./Pages/AdminPages/AdminProjectPage.tsx"; +import NotFoundPage from "./Pages/NotFoundPage.tsx"; // This is where the routes are mounted const router = createBrowserRouter([ { path: "/", element: , + errorElement: , }, { path: "/admin", From d64ec708a160ad4fd48293dbe22b9212b48761e7 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 19:37:37 +0100 Subject: [PATCH 05/63] Minor fixes --- frontend/src/Pages/YourProjectsPage.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index aabc606..e45d237 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -7,10 +7,10 @@ import BasicWindow from "../Components/BasicWindow"; export const ProjectNameContext = createContext(""); function UserProjectPage(): JSX.Element { - const [projects, setProjects] = useState([]); - const [selectedProject, setSelectedProject] = useState(""); + /* const [projects, setProjects] = useState([]); + */ const [selectedProject, setSelectedProject] = useState(""); - const getProjects = async (): Promise => { + /* const getProjects = async (): Promise => { const username = localStorage.getItem("username") ?? ""; // replace with actual username const token = localStorage.getItem("accessToken") ?? ""; // replace with actual token const response = await api.getUserProjects(username, token); @@ -24,7 +24,15 @@ function UserProjectPage(): JSX.Element { // Call getProjects when the component mounts useEffect(() => { getProjects(); - }, []); + }, []); */ + + // Mock data + const projects: Project[] = [ + { id: "1", name: "Project 1" }, + { id: "2", name: "Project 2" }, + { id: "3", name: "Project 3" }, + // Add more mock projects as needed + ]; const handleProjectClick = (projectName: string): void => { setSelectedProject(projectName); From 2aade5d2fe6d694ca232ac676c9b857c86713136 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 19:59:14 +0100 Subject: [PATCH 06/63] Docs example --- backend/docs/docs.go | 24 +++++++++++++++++++ .../handlers/handlers_user_related.go | 7 +++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 8026f58..75908b4 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -32,6 +32,17 @@ const docTemplate = `{ "User" ], "summary": "Register a new user", + "parameters": [ + { + "description": "User to register", + "name": "{string}", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.NewUser" + } + } + ], "responses": { "200": { "description": "User added", @@ -55,6 +66,19 @@ const docTemplate = `{ } } }, + "definitions": { + "types.NewUser": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + }, "externalDocs": { "description": "OpenAPI", "url": "https://swagger.io/resources/open-api/" diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 0f7c047..e454f9f 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -16,9 +16,10 @@ import ( // @Tags User // @Accept json // @Produce json -// @Success 200 {string} string "User added" -// @Failure 400 {string} string "Bad request" -// @Failure 500 {string} string "Internal server error" +// @Param {string} body types.NewUser true "User to register" +// @Success 200 {string} string "User added" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" // @Router /api/register [post] func (gs *GState) Register(c *fiber.Ctx) error { u := new(types.NewUser) From 2be4afd0e0892a35d4ec23e1f0aa2459fffe6418 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 20:05:47 +0100 Subject: [PATCH 07/63] Correct ish swagger docstring --- backend/internal/handlers/handlers_user_related.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index e454f9f..9c98d4d 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -15,12 +15,12 @@ import ( // @Description Register a new user // @Tags User // @Accept json -// @Produce json -// @Param {string} body types.NewUser true "User to register" +// @Produce plain +// @Param NewUser body types.NewUser true "User to register" // @Success 200 {string} string "User added" // @Failure 400 {string} string "Bad request" // @Failure 500 {string} string "Internal server error" -// @Router /api/register [post] +// @Router /register [post] func (gs *GState) Register(c *fiber.Ctx) error { u := new(types.NewUser) if err := c.BodyParser(u); err != nil { From 4683dd459ac565cfacab98a835a8d17bd27fe84e Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 20:56:00 +0100 Subject: [PATCH 08/63] Remove code related to demo button in backend --- backend/internal/handlers/global_state.go | 22 +++++----------------- backend/main.go | 6 +----- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 566d549..932451d 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -34,29 +34,17 @@ type GlobalState interface { // UpdateCollection(c *fiber.Ctx) error // To update a collection // DeleteCollection(c *fiber.Ctx) error // To delete a collection // SignCollection(c *fiber.Ctx) error // To sign a collection - GetButtonCount(c *fiber.Ctx) error // For demonstration purposes - IncrementButtonCount(c *fiber.Ctx) error // For demonstration purposes - ListAllUsers(c *fiber.Ctx) error // To get a list of all users in the application database - ListAllUsersProject(c *fiber.Ctx) error // To get a list of all users for a specific project - ProjectRoleChange(c *fiber.Ctx) error // To change a users role in a project + ListAllUsers(c *fiber.Ctx) error // To get a list of all users in the application database + ListAllUsersProject(c *fiber.Ctx) error // To get a list of all users for a specific project + ProjectRoleChange(c *fiber.Ctx) error // To change a users role in a project } // "Constructor" func NewGlobalState(db database.Database) GlobalState { - return &GState{Db: db, ButtonCount: 0} + return &GState{Db: db} } // The global state, which implements all the handlers type GState struct { - Db database.Database - ButtonCount int -} - -func (gs *GState) GetButtonCount(c *fiber.Ctx) error { - return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount}) -} - -func (gs *GState) IncrementButtonCount(c *fiber.Ctx) error { - gs.ButtonCount++ - return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount}) + Db database.Database } diff --git a/backend/main.go b/backend/main.go index 3e2fb75..da89043 100644 --- a/backend/main.go +++ b/backend/main.go @@ -61,11 +61,6 @@ func main() { // Register our unprotected routes server.Post("/api/register", gs.Register) - - // Register handlers for example button count - server.Get("/api/button", gs.GetButtonCount) - server.Post("/api/button", gs.IncrementButtonCount) - server.Post("/api/login", gs.Login) // Every route from here on will require a valid JWT @@ -73,6 +68,7 @@ func main() { SigningKey: jwtware.SigningKey{Key: []byte("secret")}, })) + // Protected routes (require a valid JWT bearer token authentication header) server.Post("/api/submitReport", gs.SubmitWeeklyReport) server.Get("/api/getUserProjects", gs.GetUserProjects) server.Post("/api/loginrenew", gs.LoginRenew) From 8eb23bf7f9ae41f616ab37bf489e180bd11d3022 Mon Sep 17 00:00:00 2001 From: al8763be Date: Mon, 18 Mar 2024 21:08:33 +0100 Subject: [PATCH 09/63] lint bro happ + test for getUserProject --- frontend/src/API/API.ts | 6 +++++- frontend/src/Components/EditWeeklyReport.tsx | 4 ++-- frontend/src/Components/NewWeeklyReport.tsx | 2 +- .../src/Components/UserProjectListAdmin.tsx | 2 +- frontend/src/Pages/YourProjectsPage.tsx | 4 ++-- testing.py | 17 +++++++++++------ 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index b3cb776..6078513 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -150,7 +150,10 @@ export const api: API = { } }, - async getUserProjects(token: string): Promise> { + async getUserProjects( + username: string, + token: string, + ): Promise> { try { const response = await fetch("/api/getUserProjects", { method: "GET", @@ -158,6 +161,7 @@ export const api: API = { "Content-Type": "application/json", Authorization: "Bearer " + token, }, + body: JSON.stringify({ username }), }); if (!response.ok) { diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index 9321d73..b0e8771 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -50,8 +50,8 @@ export default function GetWeeklyReport(): JSX.Element { } }; - fetchWeeklyReport(); - }, []); + void fetchWeeklyReport(); + }, [projectName, token, username, week]); const handleNewWeeklyReport = async (): Promise => { const newWeeklyReport: NewWeeklyReport = { diff --git a/frontend/src/Components/NewWeeklyReport.tsx b/frontend/src/Components/NewWeeklyReport.tsx index 4f919aa..0a84b48 100644 --- a/frontend/src/Components/NewWeeklyReport.tsx +++ b/frontend/src/Components/NewWeeklyReport.tsx @@ -1,5 +1,5 @@ import { useState, useContext } from "react"; -import { NewWeeklyReport } from "../Types/goTypes"; +import type { NewWeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; import { useNavigate } from "react-router-dom"; import Button from "./Button"; diff --git a/frontend/src/Components/UserProjectListAdmin.tsx b/frontend/src/Components/UserProjectListAdmin.tsx index 423e793..69258a1 100644 --- a/frontend/src/Components/UserProjectListAdmin.tsx +++ b/frontend/src/Components/UserProjectListAdmin.tsx @@ -9,7 +9,7 @@ const UserProjectListAdmin: React.FC = () => { const fetchProjects = async (): Promise => { try { const token = localStorage.getItem("accessToken") ?? ""; - const username = getUsernameFromContext(); // Assuming you have a function to get the username from your context + const username = "NoUser"; // getUsernameFromContext(); // Assuming you have a function to get the username from your context const response = await api.getUserProjects(username, token); if (response.success) { diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index aabc606..4c6e77f 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -1,4 +1,4 @@ -import React, { useState, createContext, useEffect } from "react"; +import { useState, createContext, useEffect } from "react"; import { Project } from "../Types/goTypes"; import { api } from "../API/API"; import { Link } from "react-router-dom"; @@ -23,7 +23,7 @@ function UserProjectPage(): JSX.Element { }; // Call getProjects when the component mounts useEffect(() => { - getProjects(); + void getProjects(); }, []); const handleProjectClick = (projectName: string): void => { diff --git a/testing.py b/testing.py index e342598..6381afc 100644 --- a/testing.py +++ b/testing.py @@ -22,13 +22,11 @@ loginPath = base_url + "/api/login" addProjectPath = base_url + "/api/project" submitReportPath = base_url + "/api/submitReport" getWeeklyReportPath = base_url + "/api/getWeeklyReport" -<<<<<<< HEAD getProjectPath = base_url + "/api/project" -======= signReportPath = base_url + "/api/signReport" addUserToProjectPath = base_url + "/api/addUserToProject" promoteToAdminPath = base_url + "/api/promoteToAdmin" ->>>>>>> 9ad89d60636ac6091d71b0bf307982becc9b89fe +getUserProjectsPath = base_url + "/api/getUserProjects" # Posts the username and password to the register endpoint @@ -150,6 +148,16 @@ def test_add_user_to_project(): assert response.status_code == 200, "Add user to project failed" print("Add user to project successful") + # Check if the user is added to the project + response = requests.get( + getUserProjectsPath, + json={"username": new_user}, + headers={"Authorization": "Bearer " + admin_token}, + ) + print(response.text) + assert response.status_code == 200, "Get user projects failed" + print("got user projects successfully") + # Test function to sign a report def test_sign_report(): # Create a project manager user @@ -232,9 +240,6 @@ if __name__ == "__main__": test_add_project() test_submit_report() test_get_weekly_report() -<<<<<<< HEAD test_get_project() -======= test_sign_report() test_add_user_to_project() ->>>>>>> 9ad89d60636ac6091d71b0bf307982becc9b89fe From e0de61dd94c97600b551ddf10d0061a4362f03f9 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 21:24:26 +0100 Subject: [PATCH 10/63] Type fixes in frontend, Register & YourProjectsPage --- frontend/src/Components/Register.tsx | 4 ++-- frontend/src/Pages/YourProjectsPage.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx index facca39..7b003cb 100644 --- a/frontend/src/Components/Register.tsx +++ b/frontend/src/Components/Register.tsx @@ -48,7 +48,7 @@ export default function Register(): JSX.Element { { setUsername(e.target.value); }} @@ -56,7 +56,7 @@ export default function Register(): JSX.Element { { setPassword(e.target.value); }} diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index 4c6e77f..32ba0ed 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -53,7 +53,7 @@ function UserProjectPage(): JSX.Element { const buttons = <>; - return ; + return ; } export default UserProjectPage; From 25713443e21eed8830c2b33f54470534727659f6 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:33:20 +0100 Subject: [PATCH 11/63] Remove username prop from BasicWindow component --- frontend/src/Components/BasicWindow.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/Components/BasicWindow.tsx b/frontend/src/Components/BasicWindow.tsx index 1835d6a..d5fd3b6 100644 --- a/frontend/src/Components/BasicWindow.tsx +++ b/frontend/src/Components/BasicWindow.tsx @@ -2,17 +2,15 @@ import Header from "./Header"; import Footer from "./Footer"; function BasicWindow({ - username, content, buttons, }: { - username: string; content: React.ReactNode; buttons: React.ReactNode; }): JSX.Element { return (
    -
    +
    {content}
    {buttons}
    From b9d7e57f2cfb6c09ce9b60fafdce93f2ca7c253e Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:37:31 +0100 Subject: [PATCH 12/63] Update background image in Header component --- frontend/src/Components/Header.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/Components/Header.tsx b/frontend/src/Components/Header.tsx index 819c5de..5cdb421 100644 --- a/frontend/src/Components/Header.tsx +++ b/frontend/src/Components/Header.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import { Link } from "react-router-dom"; +import backgroundImage from "../assets/1.jpg"; function Header(): JSX.Element { const [isOpen, setIsOpen] = useState(false); @@ -11,7 +12,7 @@ function Header(): JSX.Element { return (
    Date: Mon, 18 Mar 2024 21:37:52 +0100 Subject: [PATCH 13/63] Update user navigation route --- frontend/src/Pages/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/App.tsx b/frontend/src/Pages/App.tsx index 4263815..69fd698 100644 --- a/frontend/src/Pages/App.tsx +++ b/frontend/src/Pages/App.tsx @@ -13,7 +13,7 @@ function App(): JSX.Element { } else if (authority === 2) { navigate("/pm"); } else if (authority === 3) { - navigate("/user"); + navigate("/yourProjects"); } }, [authority, navigate]); From 93addc98704f7feac829a97285709b808032c141 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:40:07 +0100 Subject: [PATCH 14/63] Fixes in NewWeeklyReport component --- frontend/src/Components/NewWeeklyReport.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/src/Components/NewWeeklyReport.tsx b/frontend/src/Components/NewWeeklyReport.tsx index 4f919aa..86322e7 100644 --- a/frontend/src/Components/NewWeeklyReport.tsx +++ b/frontend/src/Components/NewWeeklyReport.tsx @@ -1,9 +1,8 @@ -import { useState, useContext } from "react"; +import { useState } from "react"; import { NewWeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import Button from "./Button"; -import { ProjectNameContext } from "../Pages/YourProjectsPage"; export default function NewWeeklyReport(): JSX.Element { const [week, setWeek] = useState(0); @@ -14,12 +13,12 @@ export default function NewWeeklyReport(): JSX.Element { const [studyTime, setStudyTime] = useState(0); const [testingTime, setTestingTime] = useState(0); - const projectName = useContext(ProjectNameContext); + const { projectName } = useParams(); const token = localStorage.getItem("accessToken") ?? ""; const handleNewWeeklyReport = async (): Promise => { const newWeeklyReport: NewWeeklyReport = { - projectName, + projectName: projectName ?? "", week, developmentTime, meetingTime, @@ -46,7 +45,7 @@ export default function NewWeeklyReport(): JSX.Element { } e.preventDefault(); void handleNewWeeklyReport(); - navigate("/project"); + navigate(-1); }} >
    From 31c5a78dae812238a65ff71b448d1102296903f1 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:52:34 +0100 Subject: [PATCH 15/63] Refactor routing paths in main.tsx --- frontend/src/main.tsx | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index a1e466e..1c39ae9 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -46,30 +46,26 @@ const router = createBrowserRouter([ path: "/pm", element: , }, - { - path: "/user", - element: , - }, { path: "/yourProjects", element: , }, { - path: "/editTimeReport", - element: , - }, - { - path: "/newTimeReport", - element: , - }, - { - path: "/project", + path: "/project/:projectName", element: , }, { - path: "/projectPage", + path: "/newTimeReport/:projectName", + element: , + }, + { + path: "/projectPage/:projectName", element: , }, + { + path: "/editTimeReport", + element: , + }, { path: "/changeRole", element: , From f16dc1722cb073659e984464dd7faf2c0a2c1056 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:53:16 +0100 Subject: [PATCH 16/63] Update project name in YourProjectsPage.tsx URL --- frontend/src/Pages/YourProjectsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index e45d237..9e33696 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -28,7 +28,7 @@ function UserProjectPage(): JSX.Element { // Mock data const projects: Project[] = [ - { id: "1", name: "Project 1" }, + { id: "1", name: "Project Test App" }, { id: "2", name: "Project 2" }, { id: "3", name: "Project 3" }, // Add more mock projects as needed @@ -44,7 +44,7 @@ function UserProjectPage(): JSX.Element {
    {projects.map((project, index) => ( { handleProjectClick(project.name); }} From 6982d2101666aaacee94485436fb5c6b247ca82c Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:55:15 +0100 Subject: [PATCH 17/63] Add project name to URL in UserProjectPage --- frontend/src/Pages/UserPages/UserProjectPage.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/Pages/UserPages/UserProjectPage.tsx b/frontend/src/Pages/UserPages/UserProjectPage.tsx index eab866b..51effff 100644 --- a/frontend/src/Pages/UserPages/UserProjectPage.tsx +++ b/frontend/src/Pages/UserPages/UserProjectPage.tsx @@ -1,18 +1,20 @@ -import { Link, useLocation } from "react-router-dom"; +import { Link, useLocation, useParams } from "react-router-dom"; import BasicWindow from "../../Components/BasicWindow"; import BackButton from "../../Components/BackButton"; function UserProjectPage(): JSX.Element { + const { projectName } = useParams(); + const content = ( <>

    {useLocation().state}

    - +

    Your Time Reports

    - +

    New Time Report

    From 59add3b6b3912094862c0db49ca03f03acf6ee0c Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:55:47 +0100 Subject: [PATCH 18/63] Remove username prop from BasicWindow component --- frontend/src/Pages/UserPages/UserProjectPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/UserPages/UserProjectPage.tsx b/frontend/src/Pages/UserPages/UserProjectPage.tsx index 51effff..80a0035 100644 --- a/frontend/src/Pages/UserPages/UserProjectPage.tsx +++ b/frontend/src/Pages/UserPages/UserProjectPage.tsx @@ -29,6 +29,6 @@ function UserProjectPage(): JSX.Element { ); - return ; + return ; } export default UserProjectPage; From 5a4049eaf3f77356816d2b026443dfe2816c6a8f Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 21:56:37 +0100 Subject: [PATCH 19/63] Remove username prop from BasicWindow component --- frontend/src/Pages/YourProjectsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index 9e33696..d64df81 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -61,7 +61,7 @@ function UserProjectPage(): JSX.Element { const buttons = <>; - return ; + return ; } export default UserProjectPage; From 55fd42090d640e9c8aebde10eea3f474a3cda600 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 22:00:58 +0100 Subject: [PATCH 20/63] Remove username prop from BasicWindow component on all pages --- frontend/src/Pages/AdminPages/AdminAddProject.tsx | 2 +- frontend/src/Pages/AdminPages/AdminAddUser.tsx | 2 +- frontend/src/Pages/AdminPages/AdminChangeUsername.tsx | 2 +- frontend/src/Pages/AdminPages/AdminManageProjects.tsx | 2 +- frontend/src/Pages/AdminPages/AdminManageUsers.tsx | 2 +- frontend/src/Pages/AdminPages/AdminMenuPage.tsx | 2 +- frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx | 2 +- frontend/src/Pages/AdminPages/AdminProjectChangeUserRole.tsx | 2 +- frontend/src/Pages/AdminPages/AdminProjectManageMembers.tsx | 2 +- frontend/src/Pages/AdminPages/AdminProjectPage.tsx | 2 +- frontend/src/Pages/AdminPages/AdminProjectStatistics.tsx | 2 +- frontend/src/Pages/AdminPages/AdminProjectViewMemberInfo.tsx | 2 +- frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx | 2 +- frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx | 2 +- frontend/src/Pages/ProjectManagerPages/PMOtherUsersTR.tsx | 2 +- frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx | 2 +- frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx | 2 +- .../src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx | 4 ++-- frontend/src/Pages/ProjectManagerPages/PMTotalTimeRole.tsx | 2 +- frontend/src/Pages/ProjectManagerPages/PMUnsignedReports.tsx | 2 +- .../src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx | 3 ++- frontend/src/Pages/UserPages/UserEditTimeReportPage.tsx | 2 +- frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx | 2 +- frontend/src/Pages/UserPages/UserViewTimeReportsPage.tsx | 2 +- 24 files changed, 26 insertions(+), 25 deletions(-) diff --git a/frontend/src/Pages/AdminPages/AdminAddProject.tsx b/frontend/src/Pages/AdminPages/AdminAddProject.tsx index 6df8851..aedbd3f 100644 --- a/frontend/src/Pages/AdminPages/AdminAddProject.tsx +++ b/frontend/src/Pages/AdminPages/AdminAddProject.tsx @@ -11,6 +11,6 @@ function AdminAddProject(): JSX.Element { ); - return ; + return ; } export default AdminAddProject; diff --git a/frontend/src/Pages/AdminPages/AdminAddUser.tsx b/frontend/src/Pages/AdminPages/AdminAddUser.tsx index c0f9492..38f00d5 100644 --- a/frontend/src/Pages/AdminPages/AdminAddUser.tsx +++ b/frontend/src/Pages/AdminPages/AdminAddUser.tsx @@ -21,6 +21,6 @@ function AdminAddUser(): JSX.Element { ); - return ; + return ; } export default AdminAddUser; diff --git a/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx b/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx index 2e03a8c..1756433 100644 --- a/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx +++ b/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx @@ -23,6 +23,6 @@ function AdminChangeUsername(): JSX.Element { ); - return ; + return ; } export default AdminChangeUsername; diff --git a/frontend/src/Pages/AdminPages/AdminManageProjects.tsx b/frontend/src/Pages/AdminPages/AdminManageProjects.tsx index c5cba2e..177f55b 100644 --- a/frontend/src/Pages/AdminPages/AdminManageProjects.tsx +++ b/frontend/src/Pages/AdminPages/AdminManageProjects.tsx @@ -21,6 +21,6 @@ function AdminManageProjects(): JSX.Element { ); - return ; + return ; } export default AdminManageProjects; diff --git a/frontend/src/Pages/AdminPages/AdminManageUsers.tsx b/frontend/src/Pages/AdminPages/AdminManageUsers.tsx index e62a54c..0939d77 100644 --- a/frontend/src/Pages/AdminPages/AdminManageUsers.tsx +++ b/frontend/src/Pages/AdminPages/AdminManageUsers.tsx @@ -36,6 +36,6 @@ function AdminManageUsers(): JSX.Element { ); - return ; + return ; } export default AdminManageUsers; diff --git a/frontend/src/Pages/AdminPages/AdminMenuPage.tsx b/frontend/src/Pages/AdminPages/AdminMenuPage.tsx index a8da80e..ed2118d 100644 --- a/frontend/src/Pages/AdminPages/AdminMenuPage.tsx +++ b/frontend/src/Pages/AdminPages/AdminMenuPage.tsx @@ -22,6 +22,6 @@ function AdminMenuPage(): JSX.Element { const buttons = <>; - return ; + return ; } export default AdminMenuPage; diff --git a/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx b/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx index 63fdb4b..96167cb 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx @@ -23,6 +23,6 @@ function AdminProjectAddMember(): JSX.Element { ); - return ; + return ; } export default AdminProjectAddMember; diff --git a/frontend/src/Pages/AdminPages/AdminProjectChangeUserRole.tsx b/frontend/src/Pages/AdminPages/AdminProjectChangeUserRole.tsx index dd80fa9..dd355e8 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectChangeUserRole.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectChangeUserRole.tsx @@ -23,6 +23,6 @@ function AdminProjectChangeUserRole(): JSX.Element { ); - return ; + return ; } export default AdminProjectChangeUserRole; diff --git a/frontend/src/Pages/AdminPages/AdminProjectManageMembers.tsx b/frontend/src/Pages/AdminPages/AdminProjectManageMembers.tsx index 717e8c5..c89e4c4 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectManageMembers.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectManageMembers.tsx @@ -23,6 +23,6 @@ function AdminProjectManageMembers(): JSX.Element { ); - return ; + return ; } export default AdminProjectManageMembers; diff --git a/frontend/src/Pages/AdminPages/AdminProjectPage.tsx b/frontend/src/Pages/AdminPages/AdminProjectPage.tsx index 0b15aeb..a1266ad 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectPage.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectPage.tsx @@ -23,6 +23,6 @@ function AdminProjectPage(): JSX.Element { ); - return ; + return ; } export default AdminProjectPage; diff --git a/frontend/src/Pages/AdminPages/AdminProjectStatistics.tsx b/frontend/src/Pages/AdminPages/AdminProjectStatistics.tsx index a5d9f95..dbf3428 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectStatistics.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectStatistics.tsx @@ -16,6 +16,6 @@ function AdminProjectStatistics(): JSX.Element { ); - return ; + return ; } export default AdminProjectStatistics; diff --git a/frontend/src/Pages/AdminPages/AdminProjectViewMemberInfo.tsx b/frontend/src/Pages/AdminPages/AdminProjectViewMemberInfo.tsx index e15ef35..1c9f28c 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectViewMemberInfo.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectViewMemberInfo.tsx @@ -23,6 +23,6 @@ function AdminProjectViewMemberInfo(): JSX.Element { ); - return ; + return ; } export default AdminProjectViewMemberInfo; diff --git a/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx b/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx index 44cd2fa..8b7cd8a 100644 --- a/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx +++ b/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx @@ -26,6 +26,6 @@ function AdminViewUserInfo(): JSX.Element { ); - return ; + return ; } export default AdminViewUserInfo; diff --git a/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx b/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx index 606e474..9f233a1 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx @@ -18,6 +18,6 @@ function ChangeRole(): JSX.Element { ); - return ; + return ; } export default ChangeRole; diff --git a/frontend/src/Pages/ProjectManagerPages/PMOtherUsersTR.tsx b/frontend/src/Pages/ProjectManagerPages/PMOtherUsersTR.tsx index 19ebbd9..c76947b 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMOtherUsersTR.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMOtherUsersTR.tsx @@ -10,6 +10,6 @@ function PMOtherUsersTR(): JSX.Element { ); - return ; + return ; } export default PMOtherUsersTR; diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx index bbafd6a..9fe96cf 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx @@ -30,6 +30,6 @@ function PMProjectMembers(): JSX.Element { ); - return ; + return ; } export default PMProjectMembers; diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx index 8e724f3..bd4e6ef 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx @@ -31,6 +31,6 @@ function PMProjectPage(): JSX.Element { ); - return ; + return ; } export default PMProjectPage; diff --git a/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx b/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx index 35ed6ac..44d2cda 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx @@ -1,6 +1,6 @@ import BasicWindow from "../../Components/BasicWindow"; -import Button from "../../Components/Button"; import TimeReport from "../../Components/NewWeeklyReport"; +import BackButton from "../../Components/BackButton"; function PMTotalTimeActivity(): JSX.Element { const content = ( @@ -18,6 +18,6 @@ function PMTotalTimeActivity(): JSX.Element { ); - return ; + return ; } export default PMTotalTimeActivity; diff --git a/frontend/src/Pages/ProjectManagerPages/PMTotalTimeRole.tsx b/frontend/src/Pages/ProjectManagerPages/PMTotalTimeRole.tsx index 05d902f..c0161f8 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMTotalTimeRole.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMTotalTimeRole.tsx @@ -10,6 +10,6 @@ function PMTotalTimeRole(): JSX.Element { ); - return ; + return ; } export default PMTotalTimeRole; diff --git a/frontend/src/Pages/ProjectManagerPages/PMUnsignedReports.tsx b/frontend/src/Pages/ProjectManagerPages/PMUnsignedReports.tsx index fae3842..713efec 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMUnsignedReports.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMUnsignedReports.tsx @@ -10,6 +10,6 @@ function PMUnsignedReports(): JSX.Element { ); - return ; + return ; } export default PMUnsignedReports; diff --git a/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx b/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx index 9ca963c..6e28071 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx @@ -1,6 +1,7 @@ import BasicWindow from "../../Components/BasicWindow"; import Button from "../../Components/Button"; import TimeReport from "../../Components/NewWeeklyReport"; +import BackButton from "../../Components/BackButton"; function PMViewUnsignedReport(): JSX.Element { const content = ( @@ -32,6 +33,6 @@ function PMViewUnsignedReport(): JSX.Element { ); - return ; + return ; } export default PMViewUnsignedReport; diff --git a/frontend/src/Pages/UserPages/UserEditTimeReportPage.tsx b/frontend/src/Pages/UserPages/UserEditTimeReportPage.tsx index e1b1d66..317cec8 100644 --- a/frontend/src/Pages/UserPages/UserEditTimeReportPage.tsx +++ b/frontend/src/Pages/UserPages/UserEditTimeReportPage.tsx @@ -16,6 +16,6 @@ function UserEditTimeReportPage(): JSX.Element { ); - return ; + return ; } export default UserEditTimeReportPage; diff --git a/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx b/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx index e54b207..2cdeb15 100644 --- a/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx +++ b/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx @@ -25,6 +25,6 @@ function UserNewTimeReportPage(): JSX.Element { ); - return ; + return ; } export default UserNewTimeReportPage; diff --git a/frontend/src/Pages/UserPages/UserViewTimeReportsPage.tsx b/frontend/src/Pages/UserPages/UserViewTimeReportsPage.tsx index 1d2c3f4..ca326a0 100644 --- a/frontend/src/Pages/UserPages/UserViewTimeReportsPage.tsx +++ b/frontend/src/Pages/UserPages/UserViewTimeReportsPage.tsx @@ -15,6 +15,6 @@ function UserViewTimeReportsPage(): JSX.Element { ); - return ; + return ; } export default UserViewTimeReportsPage; From c31f145c358bdaabf70122b7c70bbcd3703ccc6e Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 22:07:02 +0100 Subject: [PATCH 21/63] Database sample data, make target and go code --- backend/Makefile | 9 ++++ backend/internal/database/db.go | 43 +++++++++++++++++++ .../database/sample_data/0010_sample_data.sql | 7 +++ backend/main.go | 5 +++ 4 files changed, 64 insertions(+) create mode 100644 backend/internal/database/sample_data/0010_sample_data.sql diff --git a/backend/Makefile b/backend/Makefile index da0e254..65a2f3c 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -10,6 +10,7 @@ DB_FILE = db.sqlite3 # Directory containing migration SQL scripts MIGRATIONS_DIR = internal/database/migrations +SAMPLE_DATA_DIR = internal/database/sample_data # Build target build: @@ -54,6 +55,14 @@ migrate: sqlite3 $(DB_FILE) < $$file; \ done +sampledata: + @echo "If this ever fails, run make clean and try again" + @echo "Migrating database $(DB_FILE) using SQL scripts in $(SAMPLE_DATA_DIR)" + @for file in $(wildcard $(SAMPLE_DATA_DIR)/*.sql); do \ + echo "Applying migration: $$file"; \ + sqlite3 $(DB_FILE) < $$file; \ + done + # Target added primarily for CI/CD to ensure that the database is created before running tests db.sqlite3: make migrate diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index e2aa366..95cf8ed 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -20,6 +20,7 @@ type Database interface { GetUserId(username string) (int, error) AddProject(name string, description string, username string) error Migrate() error + MigrateSampleData() error GetProjectId(projectname string) (int, error) AddWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error AddUserToProject(username string, projectname string, role string) error @@ -49,6 +50,9 @@ type UserProjectMember struct { //go:embed migrations var scripts embed.FS +//go:embed sample_data +var sampleData embed.FS + // TODO: Possibly break these out into separate files bundled with the embed package? const userInsert = "INSERT INTO users (username, password) VALUES (?, ?)" const projectInsert = "INSERT INTO projects (name, description, owner_user_id) SELECT ?, ?, id FROM users WHERE username = ?" @@ -378,3 +382,42 @@ func (d *Db) Migrate() error { return nil } + +// MigrateSampleData applies sample data to the database. +func (d *Db) MigrateSampleData() error { + // Insert sample data + files, err := sampleData.ReadDir("sample_data") + if err != nil { + return err + } + + if len(files) == 0 { + println("No sample data files found") + } + tr := d.MustBegin() + + // Iterate over each SQL file and execute it + for _, file := range files { + if file.IsDir() || filepath.Ext(file.Name()) != ".sql" { + continue + } + + // This is perhaps not the most elegant way to do this + sqlBytes, err := sampleData.ReadFile("sample_data/" + file.Name()) + if err != nil { + return err + } + + sqlQuery := string(sqlBytes) + _, err = tr.Exec(sqlQuery) + if err != nil { + return err + } + } + + if tr.Commit() != nil { + return err + } + + return nil +} diff --git a/backend/internal/database/sample_data/0010_sample_data.sql b/backend/internal/database/sample_data/0010_sample_data.sql new file mode 100644 index 0000000..f3d9412 --- /dev/null +++ b/backend/internal/database/sample_data/0010_sample_data.sql @@ -0,0 +1,7 @@ +INSERT OR IGNORE INTO users (username, password) VALUES + ('admin', 'password'), + ('user', 'password'); + +INSERT OR IGNORE INTO projects (name, description, owner_user_id) VALUES + ('Project 1', 'Description 1', 1), + ('Project 2', 'Description 2', 2); \ No newline at end of file diff --git a/backend/main.go b/backend/main.go index da89043..24c3702 100644 --- a/backend/main.go +++ b/backend/main.go @@ -48,11 +48,16 @@ func main() { fmt.Println("Error migrating database: ", err) } + if err = db.MigrateSampleData(); err != nil { + fmt.Println("Error migrating sample data: ", err) + } + // Get our global state gs := handlers.NewGlobalState(db) // Create the server server := fiber.New() + // Mounts the swagger documentation, this is available at /swagger/index.html server.Get("/swagger/*", swagger.HandlerDefault) // Mount our static files (Beware of the security implications of this!) From f5a914330f278a5d4ab7e3ece6bb99fb26e63a7d Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 22:10:19 +0100 Subject: [PATCH 22/63] Removed userId identifier from user table, introducing numerous errors --- backend/internal/database/migrations/0010_users.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/internal/database/migrations/0010_users.sql b/backend/internal/database/migrations/0010_users.sql index d2e2dd1..a3ee5b1 100644 --- a/backend/internal/database/migrations/0010_users.sql +++ b/backend/internal/database/migrations/0010_users.sql @@ -4,7 +4,6 @@ -- password is the hashed password CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, - userId TEXT DEFAULT (HEX(RANDOMBLOB(4))) NOT NULL UNIQUE, username VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL ); From 472940cedc91f42054dd7bd43965740a7a603d91 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 22:20:25 +0100 Subject: [PATCH 23/63] Remove index from userId --- backend/internal/database/migrations/0010_users.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/internal/database/migrations/0010_users.sql b/backend/internal/database/migrations/0010_users.sql index a3ee5b1..e7c770b 100644 --- a/backend/internal/database/migrations/0010_users.sql +++ b/backend/internal/database/migrations/0010_users.sql @@ -9,5 +9,4 @@ CREATE TABLE IF NOT EXISTS users ( ); -- Users are commonly searched by username and userId -CREATE INDEX IF NOT EXISTS users_username_index ON users (username); -CREATE INDEX IF NOT EXISTS users_userId_index ON users (userId); \ No newline at end of file +CREATE INDEX IF NOT EXISTS users_username_index ON users (username); \ No newline at end of file From 7ae6cce6b42027aa4ef6345e818dc874c3839111 Mon Sep 17 00:00:00 2001 From: al8763be Date: Mon, 18 Mar 2024 22:39:02 +0100 Subject: [PATCH 24/63] Sample data --- .../database/migrations/0010_users.sql | 2 +- .../database/sample_data/0010_sample_data.sql | 53 ++++++++++++++++--- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/backend/internal/database/migrations/0010_users.sql b/backend/internal/database/migrations/0010_users.sql index a3ee5b1..93c4df8 100644 --- a/backend/internal/database/migrations/0010_users.sql +++ b/backend/internal/database/migrations/0010_users.sql @@ -10,4 +10,4 @@ CREATE TABLE IF NOT EXISTS users ( -- Users are commonly searched by username and userId CREATE INDEX IF NOT EXISTS users_username_index ON users (username); -CREATE INDEX IF NOT EXISTS users_userId_index ON users (userId); \ No newline at end of file +CREATE INDEX IF NOT EXISTS users_userId_index ON users (Id); \ No newline at end of file diff --git a/backend/internal/database/sample_data/0010_sample_data.sql b/backend/internal/database/sample_data/0010_sample_data.sql index f3d9412..d3012c6 100644 --- a/backend/internal/database/sample_data/0010_sample_data.sql +++ b/backend/internal/database/sample_data/0010_sample_data.sql @@ -1,7 +1,48 @@ -INSERT OR IGNORE INTO users (username, password) VALUES - ('admin', 'password'), - ('user', 'password'); +INSERT OR IGNORE INTO users(username, password) +VALUES ("admin", "123"); -INSERT OR IGNORE INTO projects (name, description, owner_user_id) VALUES - ('Project 1', 'Description 1', 1), - ('Project 2', 'Description 2', 2); \ No newline at end of file +INSERT OR IGNORE INTO users(username, password) +VALUES ("user", "123"); + +INSERT OR IGNORE INTO users(username, password) +VALUES ("user2", "123"); + +INSERT OR IGNORE INTO projects(name,description,owner_user_id) +VALUES ("projecttest","test project", 1) + +INSERT OR IGNORE INTO projects(name,description,owner_user_id) +VALUES ("projecttest2","test project2", 1) + +INSERT OR IGNORE INTO projects(name,description,owner_user_id) +VALUES ("projecttest3","test project3", 1) + +INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) +VALUES (1,1,"project_manager"); + +INSERT INTO user_roles(user_id,project_id,p_role) +VALUES (2,1,"member"); + +INSERT INTO user_roles(user_id,project_id,p_role) +VALUES (3,1,"member"); + +INSERT INTO user_roles(user_id,project_id,p_role) +VALUES (3,2,"member"); + +INSERT INTO user_roles(user_id,project_id,p_role) +VALUES (3,3,"member"); + +INSERT INTO user_roles(user_id,project_id,p_role) +VALUES (2,1,"project_manager"); + + +SELECT p.id, p.name, p.description +FROM projects p +JOIN user_roles ur ON p.id = ur.project_id +JOIN users u ON ur.user_id = u.id +WHERE u.username = 'admin'; + +SELECT id FROM users WHERE username = "admin" + +SELECT id FROM users WHERE username = "user" + +SELECT id FROM users WHERE username = "user2" From a5399c9335219b0301837722c98c945231409d2a Mon Sep 17 00:00:00 2001 From: al8763be Date: Mon, 18 Mar 2024 22:39:43 +0100 Subject: [PATCH 25/63] Samle data without query --- backend/internal/database/sample_data/0010_sample_data.sql | 6 ------ 1 file changed, 6 deletions(-) diff --git a/backend/internal/database/sample_data/0010_sample_data.sql b/backend/internal/database/sample_data/0010_sample_data.sql index d3012c6..0af0d66 100644 --- a/backend/internal/database/sample_data/0010_sample_data.sql +++ b/backend/internal/database/sample_data/0010_sample_data.sql @@ -35,12 +35,6 @@ INSERT INTO user_roles(user_id,project_id,p_role) VALUES (2,1,"project_manager"); -SELECT p.id, p.name, p.description -FROM projects p -JOIN user_roles ur ON p.id = ur.project_id -JOIN users u ON ur.user_id = u.id -WHERE u.username = 'admin'; - SELECT id FROM users WHERE username = "admin" SELECT id FROM users WHERE username = "user" From f3c5abf4f371ed4f763ccbe3b9684e60e2c69f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20H=C3=B6gbom=20Aronson?= Date: Mon, 18 Mar 2024 22:40:51 +0100 Subject: [PATCH 26/63] added docs for loginrenew, login, regsiter --- backend/docs/docs.go | 134 +++++++++++++++++- .../handlers/handlers_user_related.go | 40 +++++- backend/internal/types/users.go | 5 + 3 files changed, 173 insertions(+), 6 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 75908b4..ac1589c 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -19,14 +19,101 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/api/register": { + "/login": { + "post": { + "description": "logs the user in and returns a jwt token", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "login", + "parameters": [ + { + "description": "login info", + "name": "NewUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.NewUser" + } + } + ], + "responses": { + "200": { + "description": "Successfully signed token for user", + "schema": { + "type": "Token" + } + }, + "400": { + "description": "Bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } + }, + "/loginerenew": { + "post": { + "description": "renews the users token", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "renews the users token", + "responses": { + "200": { + "description": "Successfully signed token for user", + "schema": { + "type": "Token" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } + }, + "/register": { "post": { "description": "Register a new user", "consumes": [ "application/json" ], "produces": [ - "application/json" + "text/plain" ], "tags": [ "User" @@ -35,7 +122,7 @@ const docTemplate = `{ "parameters": [ { "description": "User to register", - "name": "{string}", + "name": "NewUser", "in": "body", "required": true, "schema": { @@ -64,6 +151,47 @@ const docTemplate = `{ } } } + }, + "/userdelete/{username}": { + "delete": { + "description": "UserDelete deletes a user from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "Deletes a user", + "responses": { + "200": { + "description": "User deleted", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "403": { + "description": "You can only delete yourself", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 9c98d4d..c88d3d3 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -16,7 +16,7 @@ import ( // @Tags User // @Accept json // @Produce plain -// @Param NewUser body types.NewUser true "User to register" +// @Param NewUser body types.NewUser true "User to register" // @Success 200 {string} string "User added" // @Failure 400 {string} string "Bad request" // @Failure 500 {string} string "Internal server error" @@ -39,6 +39,17 @@ func (gs *GState) Register(c *fiber.Ctx) error { // This path should obviously be protected in the future // UserDelete deletes a user from the database +// +// @Summary Deletes a user +// @Description UserDelete deletes a user from the database +// @Tags User +// @Accept json +// @Produce plain +// @Success 200 {string} string "User deleted" +// @Failure 403 {string} string "You can only delete yourself" +// @Failure 500 {string} string "Internal server error" +// @Failure 401 {string} string "Unauthorized" +// @Router /userdelete/{username} [delete] func (gs *GState) UserDelete(c *fiber.Ctx) error { // Read from path parameters username := c.Params("username") @@ -58,8 +69,21 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { } // Login is a simple login handler that returns a JWT token +// +// @Summary login +// @Description logs the user in and returns a jwt token +// @Tags User +// @Accept json +// @Param NewUser body types.NewUser true "login info" +// @Produce plain +// @Success 200 Token types.Token "Successfully signed token for user" +// @Failure 400 {string} string "Bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" +// @Router /login [post] func (gs *GState) Login(c *fiber.Ctx) error { // The body type is identical to a NewUser + u := new(types.NewUser) if err := c.BodyParser(u); err != nil { println("Error parsing body") @@ -91,10 +115,20 @@ func (gs *GState) Login(c *fiber.Ctx) error { } println("Successfully signed token for user:", u.Username) - return c.JSON(fiber.Map{"token": t}) + return c.JSON(types.Token{Token: t}) } // LoginRenew is a simple handler that renews the token +// +// @Summary renews the users token +// @Description renews the users token +// @Tags User +// @Accept json +// @Produce plain +// @Success 200 Token types.Token "Successfully signed token for user" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" +// @Router /loginerenew [post] func (gs *GState) LoginRenew(c *fiber.Ctx) error { // For testing: curl localhost:3000/restricted -H "Authorization: Bearer " user := c.Locals("user").(*jwt.Token) @@ -110,7 +144,7 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { if err != nil { return c.SendStatus(fiber.StatusInternalServerError) } - return c.JSON(fiber.Map{"token": t}) + return c.JSON(types.Token{Token: t}) } // ListAllUsers is a handler that returns a list of all users in the application database diff --git a/backend/internal/types/users.go b/backend/internal/types/users.go index e9dff67..d3f2170 100644 --- a/backend/internal/types/users.go +++ b/backend/internal/types/users.go @@ -27,3 +27,8 @@ type PublicUser struct { UserId string `json:"userId"` Username string `json:"username"` } + +// wrapper type for token +type Token struct { + Token string `json:"token"` +} From 95b09a8ce776b00f42f66188a5eccd0d673a66ac Mon Sep 17 00:00:00 2001 From: al8763be Date: Mon, 18 Mar 2024 22:46:53 +0100 Subject: [PATCH 27/63] Fixed getProjectForUsers --- backend/internal/database/db.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index 95cf8ed..25dd04b 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -64,9 +64,10 @@ const addWeeklyReport = `WITH UserLookup AS (SELECT id FROM users WHERE username const addUserToProject = "INSERT INTO user_roles (user_id, project_id, p_role) VALUES (?, ?, ?)" // WIP const changeUserRole = "UPDATE user_roles SET p_role = ? WHERE user_id = ? AND project_id = ?" -const getProjectsForUser = `SELECT projects.id, projects.name, projects.description, projects.owner_user_id - FROM projects JOIN user_roles ON projects.id = user_roles.project_id - JOIN users ON user_roles.user_id = users.id WHERE users.username = ?;` +const getProjectsForUser = `SELECT p.id, p.name, p.description FROM projects p + JOIN user_roles ur ON p.id = ur.project_id + JOIN users u ON ur.user_id = u.id + WHERE u.username = ?` // DbConnect connects to the database func DbConnect(dbpath string) Database { From 8df3311f5a41003264fdbf35f647be069b1e02b1 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 22:59:16 +0100 Subject: [PATCH 28/63] Remove duplicate code in UserProjectPage --- frontend/src/Pages/YourProjectsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index adf4482..973baa3 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -62,7 +62,6 @@ function UserProjectPage(): JSX.Element { const buttons = <>; return ; - return ; } export default UserProjectPage; From cc09eb0ead42a79912c32e052823a5295231b643 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 23:01:30 +0100 Subject: [PATCH 29/63] Remove duplicate import statements --- frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx | 1 - frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx b/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx index 5e0b6c7..676ea28 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMTotalTimeActivity.tsx @@ -1,7 +1,6 @@ import BackButton from "../../Components/BackButton"; import BasicWindow from "../../Components/BasicWindow"; import TimeReport from "../../Components/NewWeeklyReport"; -import BackButton from "../../Components/BackButton"; function PMTotalTimeActivity(): JSX.Element { const content = ( diff --git a/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx b/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx index 6276d16..aea25fb 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMViewUnsignedReport.tsx @@ -2,7 +2,6 @@ import BackButton from "../../Components/BackButton"; import BasicWindow from "../../Components/BasicWindow"; import Button from "../../Components/Button"; import TimeReport from "../../Components/NewWeeklyReport"; -import BackButton from "../../Components/BackButton"; function PMViewUnsignedReport(): JSX.Element { const content = ( From 7932350980a99f2faf85bd4c40b42bea03febabc Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 23:04:08 +0100 Subject: [PATCH 30/63] Exit with non-zero if migration fails --- backend/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/main.go b/backend/main.go index 24c3702..16a033c 100644 --- a/backend/main.go +++ b/backend/main.go @@ -46,10 +46,12 @@ func main() { // Migrate the database if err = db.Migrate(); err != nil { fmt.Println("Error migrating database: ", err) + os.Exit(1) } if err = db.MigrateSampleData(); err != nil { fmt.Println("Error migrating sample data: ", err) + os.Exit(1) } // Get our global state From 2cff1d55f9829393765180d4035308b5b1ccd46d Mon Sep 17 00:00:00 2001 From: al8763be Date: Mon, 18 Mar 2024 23:08:38 +0100 Subject: [PATCH 31/63] Fixed migration data --- .../database/sample_data/0010_sample_data.sql | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/backend/internal/database/sample_data/0010_sample_data.sql b/backend/internal/database/sample_data/0010_sample_data.sql index 0af0d66..4dac91b 100644 --- a/backend/internal/database/sample_data/0010_sample_data.sql +++ b/backend/internal/database/sample_data/0010_sample_data.sql @@ -8,35 +8,28 @@ INSERT OR IGNORE INTO users(username, password) VALUES ("user2", "123"); INSERT OR IGNORE INTO projects(name,description,owner_user_id) -VALUES ("projecttest","test project", 1) +VALUES ("projecttest","test project", 1); INSERT OR IGNORE INTO projects(name,description,owner_user_id) -VALUES ("projecttest2","test project2", 1) +VALUES ("projecttest2","test project2", 1); INSERT OR IGNORE INTO projects(name,description,owner_user_id) -VALUES ("projecttest3","test project3", 1) +VALUES ("projecttest3","test project3", 1); INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (1,1,"project_manager"); -INSERT INTO user_roles(user_id,project_id,p_role) +INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (2,1,"member"); -INSERT INTO user_roles(user_id,project_id,p_role) +INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (3,1,"member"); -INSERT INTO user_roles(user_id,project_id,p_role) +INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (3,2,"member"); -INSERT INTO user_roles(user_id,project_id,p_role) +INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (3,3,"member"); -INSERT INTO user_roles(user_id,project_id,p_role) +INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (2,1,"project_manager"); - - -SELECT id FROM users WHERE username = "admin" - -SELECT id FROM users WHERE username = "user" - -SELECT id FROM users WHERE username = "user2" From ad85194d4f5622edf7edeecad133b959c585d164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20H=C3=B6gbom=20Aronson?= Date: Mon, 18 Mar 2024 23:21:49 +0100 Subject: [PATCH 32/63] finished docs for user reletaded stucts and added endpoint for listallusers --- backend/docs/docs.go | 87 +++++++++++++++++++ .../handlers/handlers_user_related.go | 53 +++++++---- 2 files changed, 124 insertions(+), 16 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index ac1589c..1898804 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -106,6 +106,58 @@ const docTemplate = `{ } } }, + "/promoteToAdmin": { + "post": { + "description": "promote chosen user to admin", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "promote user to admin", + "parameters": [ + { + "description": "user info", + "name": "NewUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.NewUser" + } + } + ], + "responses": { + "200": { + "description": "Successfully prometed user", + "schema": { + "type": "json" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } + }, "/register": { "post": { "description": "Register a new user", @@ -192,6 +244,41 @@ const docTemplate = `{ } } } + }, + "/users/all": { + "get": { + "description": "lists all users", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "Lists users", + "responses": { + "200": { + "description": "Successfully signed token for user", + "schema": { + "type": "json" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index c88d3d3..f5a6f1b 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -16,10 +16,10 @@ import ( // @Tags User // @Accept json // @Produce plain -// @Param NewUser body types.NewUser true "User to register" -// @Success 200 {string} string "User added" -// @Failure 400 {string} string "Bad request" -// @Failure 500 {string} string "Internal server error" +// @Param NewUser body types.NewUser true "User to register" +// @Success 200 {string} string "User added" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" // @Router /register [post] func (gs *GState) Register(c *fiber.Ctx) error { u := new(types.NewUser) @@ -45,10 +45,10 @@ func (gs *GState) Register(c *fiber.Ctx) error { // @Tags User // @Accept json // @Produce plain -// @Success 200 {string} string "User deleted" -// @Failure 403 {string} string "You can only delete yourself" -// @Failure 500 {string} string "Internal server error" -// @Failure 401 {string} string "Unauthorized" +// @Success 200 {string} string "User deleted" +// @Failure 403 {string} string "You can only delete yourself" +// @Failure 500 {string} string "Internal server error" +// @Failure 401 {string} string "Unauthorized" // @Router /userdelete/{username} [delete] func (gs *GState) UserDelete(c *fiber.Ctx) error { // Read from path parameters @@ -74,12 +74,12 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { // @Description logs the user in and returns a jwt token // @Tags User // @Accept json -// @Param NewUser body types.NewUser true "login info" +// @Param NewUser body types.NewUser true "login info" // @Produce plain -// @Success 200 Token types.Token "Successfully signed token for user" -// @Failure 400 {string} string "Bad request" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" +// @Success 200 Token types.Token "Successfully signed token for user" +// @Failure 400 {string} string "Bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" // @Router /login [post] func (gs *GState) Login(c *fiber.Ctx) error { // The body type is identical to a NewUser @@ -125,9 +125,9 @@ func (gs *GState) Login(c *fiber.Ctx) error { // @Tags User // @Accept json // @Produce plain -// @Success 200 Token types.Token "Successfully signed token for user" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" +// @Success 200 Token types.Token "Successfully signed token for user" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" // @Router /loginerenew [post] func (gs *GState) LoginRenew(c *fiber.Ctx) error { // For testing: curl localhost:3000/restricted -H "Authorization: Bearer " @@ -148,6 +148,16 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { } // ListAllUsers is a handler that returns a list of all users in the application database +// +// @Summary Lists users +// @Description lists all users +// @Tags User +// @Accept json +// @Produce plain +// @Success 200 {json} json "Successfully signed token for user" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" +// @Router /users/all [get] func (gs *GState) ListAllUsers(c *fiber.Ctx) error { // Get all users from the database users, err := gs.Db.GetAllUsersApplication() @@ -159,6 +169,17 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } +// @Summary promote user to admin +// @Description promote chosen user to admin +// @Tags User +// @Accept json +// @Produce plain +// @Param NewUser body types.NewUser true "user info" +// @Success 200 {json} json "Successfully prometed user" +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" +// @Router /promoteToAdmin [post] func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error { // Extract the username from the request body var newUser types.NewUser From 9056aafd2eb470841eb2f97b7806c6a1e21a5148 Mon Sep 17 00:00:00 2001 From: al8763be Date: Mon, 18 Mar 2024 23:34:03 +0100 Subject: [PATCH 33/63] Test for getUserProjectsAdded --- testing.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/testing.py b/testing.py index 6381afc..c094dca 100644 --- a/testing.py +++ b/testing.py @@ -28,6 +28,21 @@ addUserToProjectPath = base_url + "/api/addUserToProject" promoteToAdminPath = base_url + "/api/promoteToAdmin" getUserProjectsPath = base_url + "/api/getUserProjects" +def test_get_user_projects(): + + print("Testing get user projects") + loginResponse = login("user2", "123") + # Check if the user is added to the project + response = requests.get( + getUserProjectsPath, + json={"username": "user2"}, + headers={"Authorization": "Bearer " + loginResponse.json()["token"]}, + ) + print(response.text) + print(response.json()) + assert response.status_code == 200, "Get user projects failed" + print("got user projects successfully") + # Posts the username and password to the register endpoint def register(username: string, password: string): @@ -146,17 +161,7 @@ def test_add_user_to_project(): print(response.text) assert response.status_code == 200, "Add user to project failed" - print("Add user to project successful") - - # Check if the user is added to the project - response = requests.get( - getUserProjectsPath, - json={"username": new_user}, - headers={"Authorization": "Bearer " + admin_token}, - ) - print(response.text) - assert response.status_code == 200, "Get user projects failed" - print("got user projects successfully") + print("Add user to project successful") # Test function to sign a report def test_sign_report(): @@ -235,6 +240,7 @@ def test_sign_report(): if __name__ == "__main__": + test_get_user_projects() test_create_user() test_login() test_add_project() From ff9eba039f68f10e7de6f4f174eedf7dc1b6d159 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 18 Mar 2024 23:36:59 +0100 Subject: [PATCH 34/63] Minor fixes YourProjectsPage --- frontend/src/Pages/YourProjectsPage.tsx | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index 973baa3..baf18ce 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -7,12 +7,12 @@ import BasicWindow from "../Components/BasicWindow"; export const ProjectNameContext = createContext(""); function UserProjectPage(): JSX.Element { - /* const [projects, setProjects] = useState([]); - */ const [selectedProject, setSelectedProject] = useState(""); + const [projects, setProjects] = useState([]); + const [selectedProject, setSelectedProject] = useState(""); - /* const getProjects = async (): Promise => { - const username = localStorage.getItem("username") ?? ""; // replace with actual username - const token = localStorage.getItem("accessToken") ?? ""; // replace with actual token + const getProjects = async (): Promise => { + const username = localStorage.getItem("username") ?? ""; + const token = localStorage.getItem("accessToken") ?? ""; const response = await api.getUserProjects(username, token); console.log(response); if (response.success) { @@ -24,15 +24,7 @@ function UserProjectPage(): JSX.Element { // Call getProjects when the component mounts useEffect(() => { getProjects(); - }, []); */ - - // Mock data - const projects: Project[] = [ - { id: "1", name: "Project Test App" }, - { id: "2", name: "Project 2" }, - { id: "3", name: "Project 3" }, - // Add more mock projects as needed - ]; + }, []); const handleProjectClick = (projectName: string): void => { setSelectedProject(projectName); From 0fa7558d646992bdb2f379a958cfb2b498049d87 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 23:38:50 +0100 Subject: [PATCH 35/63] Proper logging, all endpoint debug printing replaced with suitable log level --- .../handlers/handlers_project_related.go | 17 +++++------ .../handlers/handlers_report_related.go | 15 +++++----- .../handlers/handlers_user_related.go | 28 ++++++++++--------- backend/main.go | 3 ++ 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index 3732249..96f6840 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -5,6 +5,7 @@ import ( "ttime/internal/types" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" "github.com/golang-jwt/jwt/v5" ) @@ -69,7 +70,7 @@ func (gs *GState) GetProject(c *fiber.Ctx) error { if projectID == "" { return c.Status(400).SendString("No project ID provided") } - println("Getting project with ID: ", projectID) + log.Info("Getting project with ID: ", projectID) // Parse the project ID into an integer projectIDInt, err := strconv.Atoi(projectID) @@ -84,7 +85,7 @@ func (gs *GState) GetProject(c *fiber.Ctx) error { } // Return the project as JSON - println("Returning project: ", project.Name) + log.Info("Returning project: ", project.Name) return c.JSON(project) } @@ -111,7 +112,7 @@ func (gs *GState) AddUserToProjectHandler(c *fiber.Ctx) error { Role string `json:"role"` } if err := c.BodyParser(&requestData); err != nil { - println("Error parsing request body:", err) + log.Info("Error parsing request body:", err) return c.Status(400).SendString("Bad request") } @@ -119,27 +120,27 @@ func (gs *GState) AddUserToProjectHandler(c *fiber.Ctx) error { user := c.Locals("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) adminUsername := claims["name"].(string) - println("Admin username from claims:", adminUsername) + log.Info("Admin username from claims:", adminUsername) isAdmin, err := gs.Db.IsSiteAdmin(adminUsername) if err != nil { - println("Error checking admin status:", err) + log.Info("Error checking admin status:", err) return c.Status(500).SendString(err.Error()) } if !isAdmin { - println("User is not a site admin:", adminUsername) + log.Info("User is not a site admin:", adminUsername) return c.Status(403).SendString("User is not a site admin") } // Add the user to the project with the specified role err = gs.Db.AddUserToProject(requestData.Username, requestData.ProjectName, requestData.Role) if err != nil { - println("Error adding user to project:", err) + log.Info("Error adding user to project:", err) return c.Status(500).SendString(err.Error()) } // Return success message - println("User added to project successfully:", requestData.Username) + log.Info("User added to project successfully:", requestData.Username) return c.SendStatus(fiber.StatusOK) } diff --git a/backend/internal/handlers/handlers_report_related.go b/backend/internal/handlers/handlers_report_related.go index 291d068..9219bd9 100644 --- a/backend/internal/handlers/handlers_report_related.go +++ b/backend/internal/handlers/handlers_report_related.go @@ -5,6 +5,7 @@ import ( "ttime/internal/types" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" "github.com/golang-jwt/jwt/v5" ) @@ -37,16 +38,16 @@ func (gs *GState) SubmitWeeklyReport(c *fiber.Ctx) error { // Handler for retrieving weekly report func (gs *GState) GetWeeklyReport(c *fiber.Ctx) error { // Extract the necessary parameters from the request - println("GetWeeklyReport") + log.Info("GetWeeklyReport") user := c.Locals("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) username := claims["name"].(string) // Extract project name and week from query parameters projectName := c.Query("projectName") - println(projectName) + log.Info(projectName) week := c.Query("week") - println(week) + log.Info(week) // Convert week to integer weekInt, err := strconv.Atoi(week) @@ -69,7 +70,7 @@ type ReportId struct { } func (gs *GState) SignReport(c *fiber.Ctx) error { - println("Signing report...") + log.Info("Signing report...") // Extract the necessary parameters from the token user := c.Locals("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) @@ -81,9 +82,9 @@ func (gs *GState) SignReport(c *fiber.Ctx) error { if err := c.BodyParser(rid); err != nil { return err } - println("Signing report for: ", rid.ReportId) + log.Info("Signing report for: ", rid.ReportId) // reportIDInt, err := strconv.Atoi(rid.ReportId) - // println("Signing report for: ", rid.ReportId) + // log.Info("Signing report for: ", rid.ReportId) // if err != nil { // return c.Status(400).SendString("Invalid report ID") // } @@ -93,7 +94,7 @@ func (gs *GState) SignReport(c *fiber.Ctx) error { if err != nil { return c.Status(500).SendString("Failed to get project manager ID") } - println("blabla", projectManagerID) + log.Info("blabla", projectManagerID) // Call the database function to sign the weekly report err = gs.Db.SignWeeklyReport(rid.ReportId, projectManagerID) diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 0f7c047..24175ee 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -1,10 +1,11 @@ package handlers import ( - "fmt" "time" "ttime/internal/types" + "github.com/gofiber/fiber/v2/log" + "github.com/gofiber/fiber/v2" "github.com/golang-jwt/jwt/v5" ) @@ -23,16 +24,17 @@ import ( func (gs *GState) Register(c *fiber.Ctx) error { u := new(types.NewUser) if err := c.BodyParser(u); err != nil { - println("Error parsing body") + log.Warn("Error parsing body") return c.Status(400).SendString(err.Error()) } - println("Adding user:", u.Username) + log.Info("Adding user:", u.Username) + log.Info("Adding user:", u.Username) if err := gs.Db.AddUser(u.Username, u.Password); err != nil { return c.Status(500).SendString(err.Error()) } - println("User added:", u.Username) + log.Info("User added:", u.Username) return c.Status(200).SendString("User added") } @@ -61,13 +63,13 @@ func (gs *GState) Login(c *fiber.Ctx) error { // The body type is identical to a NewUser u := new(types.NewUser) if err := c.BodyParser(u); err != nil { - println("Error parsing body") + log.Warn("Error parsing body") return c.Status(400).SendString(err.Error()) } - println("Username:", u.Username) + log.Info("Username:", u.Username) if !gs.Db.CheckUser(u.Username, u.Password) { - println("User not found") + log.Info("User not found") return c.SendStatus(fiber.StatusUnauthorized) } @@ -80,16 +82,16 @@ func (gs *GState) Login(c *fiber.Ctx) error { // Create token token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - println("Token created for user:", u.Username) + log.Info("Token created for user:", u.Username) // Generate encoded token and send it as response. t, err := token.SignedString([]byte("secret")) if err != nil { - println("Error signing token") + log.Warn("Error signing token") return c.SendStatus(fiber.StatusInternalServerError) } - println("Successfully signed token for user:", u.Username) + log.Info("Successfully signed token for user:", u.Username) return c.JSON(fiber.Map{"token": t}) } @@ -132,15 +134,15 @@ func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error { } username := newUser.Username - println("Promoting user to admin:", username) // Debug print + log.Info("Promoting user to admin:", username) // Debug print // Promote the user to a site admin in the database if err := gs.Db.PromoteToAdmin(username); err != nil { - fmt.Println("Error promoting user to admin:", err) // Debug print + log.Info("Error promoting user to admin:", err) // Debug print return c.Status(500).SendString(err.Error()) } - println("User promoted to admin successfully:", username) // Debug print + log.Info("User promoted to admin successfully:", username) // Debug print // Return a success message return c.SendStatus(fiber.StatusOK) diff --git a/backend/main.go b/backend/main.go index da89043..5517dbe 100644 --- a/backend/main.go +++ b/backend/main.go @@ -10,6 +10,7 @@ import ( "github.com/BurntSushi/toml" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/swagger" jwtware "github.com/gofiber/contrib/jwt" @@ -53,6 +54,8 @@ func main() { // Create the server server := fiber.New() + server.Use(logger.New()) + server.Get("/swagger/*", swagger.HandlerDefault) // Mount our static files (Beware of the security implications of this!) From 4c297ab2efc799a56f26b81ea7cc191751666038 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 18 Mar 2024 23:39:02 +0100 Subject: [PATCH 36/63] Old unresolved merge conflict fixed --- testing.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/testing.py b/testing.py index e342598..7a8a52b 100644 --- a/testing.py +++ b/testing.py @@ -22,13 +22,10 @@ loginPath = base_url + "/api/login" addProjectPath = base_url + "/api/project" submitReportPath = base_url + "/api/submitReport" getWeeklyReportPath = base_url + "/api/getWeeklyReport" -<<<<<<< HEAD getProjectPath = base_url + "/api/project" -======= signReportPath = base_url + "/api/signReport" addUserToProjectPath = base_url + "/api/addUserToProject" promoteToAdminPath = base_url + "/api/promoteToAdmin" ->>>>>>> 9ad89d60636ac6091d71b0bf307982becc9b89fe # Posts the username and password to the register endpoint @@ -232,9 +229,6 @@ if __name__ == "__main__": test_add_project() test_submit_report() test_get_weekly_report() -<<<<<<< HEAD test_get_project() -======= test_sign_report() test_add_user_to_project() ->>>>>>> 9ad89d60636ac6091d71b0bf307982becc9b89fe From fe08d01e15ed9e293e8c02449d947bc6f002697b Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Tue, 19 Mar 2024 00:00:18 +0100 Subject: [PATCH 37/63] Insanely verbose logging --- .../handlers/handlers_project_related.go | 10 +++++++ .../handlers/handlers_report_related.go | 30 ++++++++++++------- .../handlers/handlers_user_related.go | 16 ++++++++-- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index 96f6840..f3a7ea0 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -68,6 +68,7 @@ func (gs *GState) GetProject(c *fiber.Ctx) error { // Extract the project ID from the request parameters or body projectID := c.Params("projectID") if projectID == "" { + log.Info("No project ID provided") return c.Status(400).SendString("No project ID provided") } log.Info("Getting project with ID: ", projectID) @@ -75,12 +76,14 @@ func (gs *GState) GetProject(c *fiber.Ctx) error { // Parse the project ID into an integer projectIDInt, err := strconv.Atoi(projectID) if err != nil { + log.Info("Invalid project ID") return c.Status(400).SendString("Invalid project ID") } // Get the project from the database by its ID project, err := gs.Db.GetProject(projectIDInt) if err != nil { + log.Info("Error getting project:", err) return c.Status(500).SendString(err.Error()) } @@ -92,13 +95,20 @@ func (gs *GState) GetProject(c *fiber.Ctx) error { func (gs *GState) ListAllUsersProject(c *fiber.Ctx) error { // Extract the project name from the request parameters or body projectName := c.Params("projectName") + if projectName == "" { + log.Info("No project name provided") + return c.Status(400).SendString("No project name provided") + } // Get all users associated with the project from the database users, err := gs.Db.GetAllUsersProject(projectName) if err != nil { + log.Info("Error getting users for project:", err) return c.Status(500).SendString(err.Error()) } + log.Info("Returning users for project: ", projectName) + // Return the list of users as JSON return c.JSON(users) } diff --git a/backend/internal/handlers/handlers_report_related.go b/backend/internal/handlers/handlers_report_related.go index 9219bd9..85eb6e2 100644 --- a/backend/internal/handlers/handlers_report_related.go +++ b/backend/internal/handlers/handlers_report_related.go @@ -17,50 +17,62 @@ func (gs *GState) SubmitWeeklyReport(c *fiber.Ctx) error { report := new(types.NewWeeklyReport) if err := c.BodyParser(report); err != nil { + log.Info("Error parsing weekly report") return c.Status(400).SendString(err.Error()) } // Make sure all the fields of the report are valid if report.Week < 1 || report.Week > 52 { + log.Info("Invalid week number") return c.Status(400).SendString("Invalid week number") } if report.DevelopmentTime < 0 || report.MeetingTime < 0 || report.AdminTime < 0 || report.OwnWorkTime < 0 || report.StudyTime < 0 || report.TestingTime < 0 { + log.Info("Invalid time report") return c.Status(400).SendString("Invalid time report") } if err := gs.Db.AddWeeklyReport(report.ProjectName, username, report.Week, report.DevelopmentTime, report.MeetingTime, report.AdminTime, report.OwnWorkTime, report.StudyTime, report.TestingTime); err != nil { + log.Info("Error adding weekly report") return c.Status(500).SendString(err.Error()) } + log.Info("Weekly report added") return c.Status(200).SendString("Time report added") } // Handler for retrieving weekly report func (gs *GState) GetWeeklyReport(c *fiber.Ctx) error { // Extract the necessary parameters from the request - log.Info("GetWeeklyReport") user := c.Locals("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) username := claims["name"].(string) + log.Info("Getting weekly report for: ", username) + // Extract project name and week from query parameters projectName := c.Query("projectName") - log.Info(projectName) week := c.Query("week") - log.Info(week) + + if projectName == "" || week == "" { + log.Info("Missing project name or week number") + return c.Status(400).SendString("Missing project name or week number") + } // Convert week to integer weekInt, err := strconv.Atoi(week) if err != nil { + log.Info("Invalid week number") return c.Status(400).SendString("Invalid week number") } // Call the database function to get the weekly report report, err := gs.Db.GetWeeklyReport(username, projectName, weekInt) if err != nil { + log.Info("Error getting weekly report from db:", err) return c.Status(500).SendString(err.Error()) } + log.Info("Returning weekly report") // Return the retrieved weekly report return c.JSON(report) } @@ -70,12 +82,13 @@ type ReportId struct { } func (gs *GState) SignReport(c *fiber.Ctx) error { - log.Info("Signing report...") // Extract the necessary parameters from the token user := c.Locals("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) projectManagerUsername := claims["name"].(string) + log.Info("Signing report for: ", projectManagerUsername) + // Extract report ID from the request query parameters // reportID := c.Query("reportId") rid := new(ReportId) @@ -83,22 +96,19 @@ func (gs *GState) SignReport(c *fiber.Ctx) error { return err } log.Info("Signing report for: ", rid.ReportId) - // reportIDInt, err := strconv.Atoi(rid.ReportId) - // log.Info("Signing report for: ", rid.ReportId) - // if err != nil { - // return c.Status(400).SendString("Invalid report ID") - // } // Get the project manager's ID projectManagerID, err := gs.Db.GetUserId(projectManagerUsername) if err != nil { + log.Info("Failed to get project manager ID") return c.Status(500).SendString("Failed to get project manager ID") } - log.Info("blabla", projectManagerID) + log.Info("Project manager ID: ", projectManagerID) // Call the database function to sign the weekly report err = gs.Db.SignWeeklyReport(rid.ReportId, projectManagerID) if err != nil { + log.Info("Error signing weekly report:", err) return c.Status(500).SendString(err.Error()) } diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 24175ee..8f4108c 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -28,9 +28,9 @@ func (gs *GState) Register(c *fiber.Ctx) error { return c.Status(400).SendString(err.Error()) } - log.Info("Adding user:", u.Username) log.Info("Adding user:", u.Username) if err := gs.Db.AddUser(u.Username, u.Password); err != nil { + log.Warn("Error adding user:", err) return c.Status(500).SendString(err.Error()) } @@ -48,13 +48,16 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { auth_username := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)["name"].(string) if username != auth_username { + log.Info("User tried to delete another user") return c.Status(403).SendString("You can only delete yourself") } if err := gs.Db.RemoveUser(username); err != nil { + log.Warn("Error deleting user:", err) return c.Status(500).SendString(err.Error()) } + log.Info("User deleted:", username) return c.Status(200).SendString("User deleted") } @@ -67,7 +70,7 @@ func (gs *GState) Login(c *fiber.Ctx) error { return c.Status(400).SendString(err.Error()) } - log.Info("Username:", u.Username) + log.Info("Username logging in:", u.Username) if !gs.Db.CheckUser(u.Username, u.Password) { log.Info("User not found") return c.SendStatus(fiber.StatusUnauthorized) @@ -97,8 +100,10 @@ func (gs *GState) Login(c *fiber.Ctx) error { // LoginRenew is a simple handler that renews the token func (gs *GState) LoginRenew(c *fiber.Ctx) error { - // For testing: curl localhost:3000/restricted -H "Authorization: Bearer " user := c.Locals("user").(*jwt.Token) + + log.Info("Renewing token for user:", user.Claims.(jwt.MapClaims)["name"]) + claims := user.Claims.(jwt.MapClaims) claims["exp"] = time.Now().Add(time.Hour * 72).Unix() renewed := jwt.MapClaims{ @@ -109,8 +114,11 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { token := jwt.NewWithClaims(jwt.SigningMethodHS256, renewed) t, err := token.SignedString([]byte("secret")) if err != nil { + log.Warn("Error signing token") return c.SendStatus(fiber.StatusInternalServerError) } + + log.Info("Successfully renewed token for user:", user.Claims.(jwt.MapClaims)["name"]) return c.JSON(fiber.Map{"token": t}) } @@ -119,9 +127,11 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { // Get all users from the database users, err := gs.Db.GetAllUsersApplication() if err != nil { + log.Info("Error getting users from db:", err) // Debug print return c.Status(500).SendString(err.Error()) } + log.Info("Returning all users") // Return the list of users as JSON return c.JSON(users) } From e55b380bb4148ba0e3297e81d95536b800307c06 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Tue, 19 Mar 2024 00:14:55 +0100 Subject: [PATCH 38/63] Should be able to delete users except for self now --- backend/internal/handlers/handlers_user_related.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 0619ea5..194f5d5 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -44,8 +44,8 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { // Read username from Locals auth_username := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)["name"].(string) - if username != auth_username { - return c.Status(403).SendString("You can only delete yourself") + if username == auth_username { + return c.Status(403).SendString("You can't delete yourself") } if err := gs.Db.RemoveUser(username); err != nil { From db4f86971239caad7dcdd61f3f394d75998f95f3 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Tue, 19 Mar 2024 00:15:42 +0100 Subject: [PATCH 39/63] Delete user component --- frontend/src/Components/DeleteUser.tsx | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 frontend/src/Components/DeleteUser.tsx diff --git a/frontend/src/Components/DeleteUser.tsx b/frontend/src/Components/DeleteUser.tsx new file mode 100644 index 0000000..db49724 --- /dev/null +++ b/frontend/src/Components/DeleteUser.tsx @@ -0,0 +1,34 @@ +import { User } from "../Types/goTypes"; +import { api, APIResponse } from "../API/API"; + +/** + * Use to remove a user from the system + * @param props - The username of user to remove + * @returns {boolean} True if removed, false if not + * @example + * const exampleUsername = "user"; + * DeleteUser({ usernameToDelete: exampleUsername }); + */ + +function DeleteUser(props: { usernameToDelete: string }): boolean { + //console.log(props.usernameToDelete); FOR DEBUG + let removed = false; + api + .removeUser( + props.usernameToDelete, + localStorage.getItem("accessToken") ?? "", + ) + .then((response: APIResponse) => { + if (response.success) { + removed = true; + } else { + console.error(response.message); + } + }) + .catch((error) => { + console.error("An error occurred during creation:", error); + }); + return removed; +} + +export default DeleteUser; From a0759b099af6bf9bcf96119b710347f2f1475092 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Tue, 19 Mar 2024 00:17:29 +0100 Subject: [PATCH 40/63] Modul for viewing user info in admin manage users page --- frontend/src/Components/UserInfoModal.tsx | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 frontend/src/Components/UserInfoModal.tsx diff --git a/frontend/src/Components/UserInfoModal.tsx b/frontend/src/Components/UserInfoModal.tsx new file mode 100644 index 0000000..fff6776 --- /dev/null +++ b/frontend/src/Components/UserInfoModal.tsx @@ -0,0 +1,46 @@ +import Button from "./Button"; +import DeleteUser from "./DeleteUser"; +import UserProjectListAdmin from "./UserProjectListAdmin"; + +function UserInfoModal(props: { + isVisible: boolean; + username: string; + onClose: () => void; +}): JSX.Element { + if (!props.isVisible) return <>; + + return ( +
    +
    +

    {props.username}

    +
    +

    + Member of these projects: +

    + +
    +
    +
    +
    +
    + ); +} + +export default UserInfoModal; From 83f8097c2b8e7fcd07f10c2be5b813b02fc40d69 Mon Sep 17 00:00:00 2001 From: al8763be Date: Tue, 19 Mar 2024 00:20:08 +0100 Subject: [PATCH 41/63] API getUserProjects Fucked --- frontend/src/API/API.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 6078513..a06f804 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -176,7 +176,7 @@ export const api: API = { } catch (e) { return Promise.resolve({ success: false, - message: "Failed to get user projects", + message: "API fucked", }); } }, From 36524e5cbb3ab99dbd0df10d97f8f0c3ef03b808 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Tue, 19 Mar 2024 00:25:37 +0100 Subject: [PATCH 42/63] Changed so that it makes a modal for each user instead of a link --- frontend/src/Components/UserListAdmin.tsx | 54 +++++++++++++++++------ 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/frontend/src/Components/UserListAdmin.tsx b/frontend/src/Components/UserListAdmin.tsx index b86076a..3d2bcae 100644 --- a/frontend/src/Components/UserListAdmin.tsx +++ b/frontend/src/Components/UserListAdmin.tsx @@ -1,5 +1,6 @@ -import { Link } from "react-router-dom"; +import { useState } from "react"; import { PublicUser } from "../Types/goTypes"; +import UserInfoModal from "./UserInfoModal"; /** * The props for the UserProps component @@ -9,27 +10,52 @@ interface UserProps { } /** - * A list of users for admin manage users page, that links admin to the right user page - * thanks to the state property - * @param props - The users to display + * A list of users for admin manage users page, that sets an onClick + * function for eact user
  • element, which displays a modul with + * user info. + * @param props - An array of users users to display * @returns {JSX.Element} The user list * @example - * const users = [{ id: 1, userName: "Random name" }]; + * const users = [{ id: 1, userName: "ExampleName" }]; * return ; */ export function UserListAdmin(props: UserProps): JSX.Element { + const [modalVisible, setModalVisible] = useState(false); + const [username, setUsername] = useState(""); + + const handleClick = (username: string): void => { + setUsername(username); + setModalVisible(true); + }; + + const handleClose = (): void => { + setUsername(""); + setModalVisible(false); + }; + return ( -
    -
      - {props.users.map((user) => ( - -
    • + <> + +
      +
        + {props.users.map((user) => ( +
      • { + handleClick(user.username); + }} + > {user.username}
      • - - ))} -
      -
      + ))} +
    +
    + ); } From d2ff2428cd6a08aa440c10a11b9507ea6231694a Mon Sep 17 00:00:00 2001 From: Peter KW Date: Tue, 19 Mar 2024 00:26:05 +0100 Subject: [PATCH 43/63] Some corrections --- frontend/src/Components/UserProjectListAdmin.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/Components/UserProjectListAdmin.tsx b/frontend/src/Components/UserProjectListAdmin.tsx index c4857db..e4bf58c 100644 --- a/frontend/src/Components/UserProjectListAdmin.tsx +++ b/frontend/src/Components/UserProjectListAdmin.tsx @@ -1,15 +1,15 @@ -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { api } from "../API/API"; import { Project } from "../Types/goTypes"; -const UserProjectListAdmin: React.FC = () => { +function UserProjectListAdmin(props: { username: string }): JSX.Element { const [projects, setProjects] = useState([]); useEffect(() => { const fetchProjects = async (): Promise => { try { const token = localStorage.getItem("accessToken") ?? ""; - const username = localStorage.getItem("username") ?? ""; + const username = props.username; const response = await api.getUserProjects(username, token); if (response.success) { @@ -23,7 +23,7 @@ const UserProjectListAdmin: React.FC = () => { }; void fetchProjects(); - }, []); + }); return (
    @@ -37,6 +37,6 @@ const UserProjectListAdmin: React.FC = () => {
    ); -}; +} export default UserProjectListAdmin; From 59c4dab2e26ccb942ab38d7621d27d69654f2754 Mon Sep 17 00:00:00 2001 From: al8763be Date: Tue, 19 Mar 2024 00:26:17 +0100 Subject: [PATCH 44/63] quick fix for getUserProjects API --- frontend/src/API/API.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index a06f804..cab3b6b 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -150,10 +150,7 @@ export const api: API = { } }, - async getUserProjects( - username: string, - token: string, - ): Promise> { + async getUserProjects(token: string): Promise> { try { const response = await fetch("/api/getUserProjects", { method: "GET", @@ -161,7 +158,6 @@ export const api: API = { "Content-Type": "application/json", Authorization: "Bearer " + token, }, - body: JSON.stringify({ username }), }); if (!response.ok) { From 8711f9a20d93a22ec1d24913b3c59f0b5e518b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20H=C3=B6gbom=20Aronson?= Date: Tue, 19 Mar 2024 00:27:31 +0100 Subject: [PATCH 45/63] tyding up and tryinng to get tokens in docs to work --- backend/docs/docs.go | 22 ++++++++++++++----- .../handlers/handlers_user_related.go | 11 +++++----- backend/main.go | 6 ++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 1898804..322c812 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -73,6 +73,11 @@ const docTemplate = `{ }, "/loginerenew": { "post": { + "security": [ + { + "bererToken": [] + } + ], "description": "renews the users token", "consumes": [ "application/json" @@ -83,7 +88,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "renews the users token", + "summary": "LoginRenews", "responses": { "200": { "description": "Successfully signed token for user", @@ -118,7 +123,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "promote user to admin", + "summary": "PromoteToAdmin", "parameters": [ { "description": "user info", @@ -170,7 +175,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "Register a new user", + "summary": "Register", "parameters": [ { "description": "User to register", @@ -216,7 +221,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "Deletes a user", + "summary": "UserDelete", "responses": { "200": { "description": "User deleted", @@ -257,7 +262,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "Lists users", + "summary": "ListsAllUsers", "responses": { "200": { "description": "Successfully signed token for user", @@ -294,6 +299,13 @@ const docTemplate = `{ } } }, + "securityDefinitions": { + "bererToken": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + }, "externalDocs": { "description": "OpenAPI", "url": "https://swagger.io/resources/open-api/" diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index f5a6f1b..943a977 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -11,7 +11,7 @@ import ( // Register is a simple handler that registers a new user // -// @Summary Register a new user +// @Summary Register // @Description Register a new user // @Tags User // @Accept json @@ -40,7 +40,7 @@ func (gs *GState) Register(c *fiber.Ctx) error { // This path should obviously be protected in the future // UserDelete deletes a user from the database // -// @Summary Deletes a user +// @Summary UserDelete // @Description UserDelete deletes a user from the database // @Tags User // @Accept json @@ -120,8 +120,9 @@ func (gs *GState) Login(c *fiber.Ctx) error { // LoginRenew is a simple handler that renews the token // -// @Summary renews the users token +// @Summary LoginRenews // @Description renews the users token +// @Security bererToken // @Tags User // @Accept json // @Produce plain @@ -149,7 +150,7 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { // ListAllUsers is a handler that returns a list of all users in the application database // -// @Summary Lists users +// @Summary ListsAllUsers // @Description lists all users // @Tags User // @Accept json @@ -169,7 +170,7 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } -// @Summary promote user to admin +// @Summary PromoteToAdmin // @Description promote chosen user to admin // @Tags User // @Accept json diff --git a/backend/main.go b/backend/main.go index 3e2fb75..c19533e 100644 --- a/backend/main.go +++ b/backend/main.go @@ -22,6 +22,10 @@ import ( // @license.name AGPL // @license.url https://www.gnu.org/licenses/agpl-3.0.html +//@securityDefinitions.apikey bererToken +//@in header +//@name Authorization + // @host localhost:8080 // @BasePath /api @@ -83,7 +87,7 @@ func main() { server.Post("/api/signReport", gs.SignReport) server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) - + server.Get("/api/users/all", gs.ListAllUsers) // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) if err != nil { From d7e14f18860c41e5a0416e1584bba63d9daace14 Mon Sep 17 00:00:00 2001 From: al8763be Date: Tue, 19 Mar 2024 00:27:35 +0100 Subject: [PATCH 46/63] quick fix for getUserProjects API --- frontend/src/API/API.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index cab3b6b..8fd66d3 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -42,10 +42,7 @@ interface API { token: string, ): Promise>; /** Gets all the projects of a user*/ - getUserProjects( - username: string, - token: string, - ): Promise>; + getUserProjects(token: string): Promise>; /** Gets a project from id*/ getProject(id: number): Promise>; } From 7e4e35f597a54ccb4151e2574e347efdb6ef56e5 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Tue, 19 Mar 2024 00:30:25 +0100 Subject: [PATCH 47/63] Silencing python testing, optional verbose output --- testing.py | 67 +++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/testing.py b/testing.py index 1eea03b..71b614e 100644 --- a/testing.py +++ b/testing.py @@ -2,6 +2,11 @@ import requests import string import random +debug_output = False + +def dprint(*args, **kwargs): + if debug_output: + print(*args, **kwargs) def randomString(len=10): """Generate a random string of fixed length""" @@ -31,7 +36,7 @@ getUserProjectsPath = base_url + "/api/getUserProjects" def test_get_user_projects(): - print("Testing get user projects") + dprint("Testing get user projects") loginResponse = login("user2", "123") # Check if the user is added to the project response = requests.get( @@ -39,29 +44,29 @@ def test_get_user_projects(): json={"username": "user2"}, headers={"Authorization": "Bearer " + loginResponse.json()["token"]}, ) - print(response.text) - print(response.json()) + dprint(response.text) + dprint(response.json()) assert response.status_code == 200, "Get user projects failed" - print("got user projects successfully") + dprint("got user projects successfully") # Posts the username and password to the register endpoint def register(username: string, password: string): - print("Registering with username: ", username, " and password: ", password) + dprint("Registering with username: ", username, " and password: ", password) response = requests.post( registerPath, json={"username": username, "password": password} ) - print(response.text) + dprint(response.text) return response # Posts the username and password to the login endpoint def login(username: string, password: string): - print("Logging in with username: ", username, " and password: ", password) + dprint("Logging in with username: ", username, " and password: ", password) response = requests.post( loginPath, json={"username": username, "password": password} ) - print(response.text) + dprint(response.text) return response @@ -69,7 +74,7 @@ def login(username: string, password: string): def test_login(): response = login(username, "always_same") assert response.status_code == 200, "Login failed" - print("Login successful") + dprint("Login successful") return response.json()["token"] @@ -77,8 +82,7 @@ def test_login(): def test_create_user(): response = register(username, "always_same") assert response.status_code == 200, "Registration failed" - print("Registration successful") - + dprint("Registration successful") # Test function to add a project def test_add_project(): @@ -89,10 +93,9 @@ def test_add_project(): json={"name": projectName, "description": "This is a project"}, headers={"Authorization": "Bearer " + token}, ) - print(response.text) + dprint(response.text) assert response.status_code == 200, "Add project failed" - print("Add project successful") - + dprint("Add project successful") # Test function to submit a report def test_submit_report(): @@ -111,10 +114,9 @@ def test_submit_report(): }, headers={"Authorization": "Bearer " + token}, ) - print(response.text) + dprint(response.text) assert response.status_code == 200, "Submit report failed" - print("Submit report successful") - + dprint("Submit report successful") # Test function to get a weekly report def test_get_weekly_report(): @@ -124,7 +126,7 @@ def test_get_weekly_report(): headers={"Authorization": "Bearer " + token}, params={"username": username, "projectName": projectName, "week": 1}, ) - print(response.text) + dprint(response.text) assert response.status_code == 200, "Get weekly report failed" @@ -135,7 +137,7 @@ def test_get_project(): getProjectPath + "/1", # Assumes that the project with id 1 exists headers={"Authorization": "Bearer " + token}, ) - print(response.text) + dprint(response.text) assert response.status_code == 200, "Get project failed" @@ -144,13 +146,13 @@ def test_add_user_to_project(): # Log in as a site admin admin_username = randomString() admin_password = "admin_password" - print( + dprint( "Registering with username: ", admin_username, " and password: ", admin_password ) response = requests.post( registerPath, json={"username": admin_username, "password": admin_password} ) - print(response.text) + dprint(response.text) admin_token = login(admin_username, admin_password).json()["token"] response = requests.post( @@ -158,9 +160,9 @@ def test_add_user_to_project(): json={"username": admin_username}, headers={"Authorization": "Bearer " + admin_token}, ) - print(response.text) + dprint(response.text) assert response.status_code == 200, "Promote to site admin failed" - print("Admin promoted to site admin successfully") + dprint("Admin promoted to site admin successfully") # Create a new user to add to the project new_user = randomString() @@ -173,10 +175,9 @@ def test_add_user_to_project(): headers={"Authorization": "Bearer " + admin_token}, ) - print(response.text) + dprint(response.text) assert response.status_code == 200, "Add user to project failed" - print("Add user to project successful") - + dprint("Add user to project successful") # Test function to sign a report def test_sign_report(): @@ -187,13 +188,13 @@ def test_sign_report(): # Register an admin admin_username = randomString() admin_password = "admin_password2" - print( + dprint( "Registering with username: ", admin_username, " and password: ", admin_password ) response = requests.post( registerPath, json={"username": admin_username, "password": admin_password} ) - print(response.text) + dprint(response.text) # Log in as the admin admin_token = login(admin_username, admin_password).json()["token"] @@ -213,7 +214,7 @@ def test_sign_report(): headers={"Authorization": "Bearer " + admin_token}, ) assert response.status_code == 200, "Add project manager to project failed" - print("Project manager added to project successfully") + dprint("Project manager added to project successfully") # Log in as the project manager project_manager_token = login(project_manager, "project_manager_password").json()[ @@ -237,7 +238,7 @@ def test_sign_report(): headers={"Authorization": "Bearer " + token}, ) assert response.status_code == 200, "Submit report failed" - print("Submit report successful") + dprint("Submit report successful") # Retrieve the report ID response = requests.get( @@ -245,7 +246,7 @@ def test_sign_report(): headers={"Authorization": "Bearer " + token}, params={"username": username, "projectName": projectName, "week": 1}, ) - print(response.text) + dprint(response.text) report_id = response.json()["reportId"] # Sign the report as the project manager @@ -255,7 +256,7 @@ def test_sign_report(): headers={"Authorization": "Bearer " + project_manager_token}, ) assert response.status_code == 200, "Sign report failed" - print("Sign report successful") + dprint("Sign report successful") # Retrieve the report ID again for confirmation response = requests.get( @@ -263,7 +264,7 @@ def test_sign_report(): headers={"Authorization": "Bearer " + token}, params={"username": username, "projectName": projectName, "week": 1}, ) - print(response.text) + dprint(response.text) if __name__ == "__main__": From 3e35586bbea83e73c83a61c1ff6a10a1014f16d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20H=C3=B6gbom=20Aronson?= Date: Mon, 18 Mar 2024 23:21:49 +0100 Subject: [PATCH 48/63] finished docs for user reletaded stucts and added endpoint for listallusers --- backend/docs/docs.go | 87 +++++++++++++++++++ .../handlers/handlers_user_related.go | 53 +++++++---- 2 files changed, 124 insertions(+), 16 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index ac1589c..1898804 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -106,6 +106,58 @@ const docTemplate = `{ } } }, + "/promoteToAdmin": { + "post": { + "description": "promote chosen user to admin", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "promote user to admin", + "parameters": [ + { + "description": "user info", + "name": "NewUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.NewUser" + } + } + ], + "responses": { + "200": { + "description": "Successfully prometed user", + "schema": { + "type": "json" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } + }, "/register": { "post": { "description": "Register a new user", @@ -192,6 +244,41 @@ const docTemplate = `{ } } } + }, + "/users/all": { + "get": { + "description": "lists all users", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "User" + ], + "summary": "Lists users", + "responses": { + "200": { + "description": "Successfully signed token for user", + "schema": { + "type": "json" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 1d94270..1ed6bd4 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -17,10 +17,10 @@ import ( // @Tags User // @Accept json // @Produce plain -// @Param NewUser body types.NewUser true "User to register" -// @Success 200 {string} string "User added" -// @Failure 400 {string} string "Bad request" -// @Failure 500 {string} string "Internal server error" +// @Param NewUser body types.NewUser true "User to register" +// @Success 200 {string} string "User added" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" // @Router /register [post] func (gs *GState) Register(c *fiber.Ctx) error { u := new(types.NewUser) @@ -47,10 +47,10 @@ func (gs *GState) Register(c *fiber.Ctx) error { // @Tags User // @Accept json // @Produce plain -// @Success 200 {string} string "User deleted" -// @Failure 403 {string} string "You can only delete yourself" -// @Failure 500 {string} string "Internal server error" -// @Failure 401 {string} string "Unauthorized" +// @Success 200 {string} string "User deleted" +// @Failure 403 {string} string "You can only delete yourself" +// @Failure 500 {string} string "Internal server error" +// @Failure 401 {string} string "Unauthorized" // @Router /userdelete/{username} [delete] func (gs *GState) UserDelete(c *fiber.Ctx) error { // Read from path parameters @@ -79,12 +79,12 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { // @Description logs the user in and returns a jwt token // @Tags User // @Accept json -// @Param NewUser body types.NewUser true "login info" +// @Param NewUser body types.NewUser true "login info" // @Produce plain -// @Success 200 Token types.Token "Successfully signed token for user" -// @Failure 400 {string} string "Bad request" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" +// @Success 200 Token types.Token "Successfully signed token for user" +// @Failure 400 {string} string "Bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" // @Router /login [post] func (gs *GState) Login(c *fiber.Ctx) error { // The body type is identical to a NewUser @@ -130,9 +130,9 @@ func (gs *GState) Login(c *fiber.Ctx) error { // @Tags User // @Accept json // @Produce plain -// @Success 200 Token types.Token "Successfully signed token for user" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" +// @Success 200 Token types.Token "Successfully signed token for user" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" // @Router /loginerenew [post] func (gs *GState) LoginRenew(c *fiber.Ctx) error { user := c.Locals("user").(*jwt.Token) @@ -158,6 +158,16 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { } // ListAllUsers is a handler that returns a list of all users in the application database +// +// @Summary Lists users +// @Description lists all users +// @Tags User +// @Accept json +// @Produce plain +// @Success 200 {json} json "Successfully signed token for user" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" +// @Router /users/all [get] func (gs *GState) ListAllUsers(c *fiber.Ctx) error { // Get all users from the database users, err := gs.Db.GetAllUsersApplication() @@ -171,6 +181,17 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } +// @Summary promote user to admin +// @Description promote chosen user to admin +// @Tags User +// @Accept json +// @Produce plain +// @Param NewUser body types.NewUser true "user info" +// @Success 200 {json} json "Successfully prometed user" +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal server error" +// @Router /promoteToAdmin [post] func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error { // Extract the username from the request body var newUser types.NewUser From 9ce70e74e922279f4881407b49b096ba5a4681fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20H=C3=B6gbom=20Aronson?= Date: Tue, 19 Mar 2024 00:27:31 +0100 Subject: [PATCH 49/63] tyding up and tryinng to get tokens in docs to work --- backend/docs/docs.go | 22 ++++++++++++++----- .../handlers/handlers_user_related.go | 11 +++++----- backend/main.go | 6 ++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 1898804..322c812 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -73,6 +73,11 @@ const docTemplate = `{ }, "/loginerenew": { "post": { + "security": [ + { + "bererToken": [] + } + ], "description": "renews the users token", "consumes": [ "application/json" @@ -83,7 +88,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "renews the users token", + "summary": "LoginRenews", "responses": { "200": { "description": "Successfully signed token for user", @@ -118,7 +123,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "promote user to admin", + "summary": "PromoteToAdmin", "parameters": [ { "description": "user info", @@ -170,7 +175,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "Register a new user", + "summary": "Register", "parameters": [ { "description": "User to register", @@ -216,7 +221,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "Deletes a user", + "summary": "UserDelete", "responses": { "200": { "description": "User deleted", @@ -257,7 +262,7 @@ const docTemplate = `{ "tags": [ "User" ], - "summary": "Lists users", + "summary": "ListsAllUsers", "responses": { "200": { "description": "Successfully signed token for user", @@ -294,6 +299,13 @@ const docTemplate = `{ } } }, + "securityDefinitions": { + "bererToken": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + }, "externalDocs": { "description": "OpenAPI", "url": "https://swagger.io/resources/open-api/" diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 1ed6bd4..96fddb7 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -12,7 +12,7 @@ import ( // Register is a simple handler that registers a new user // -// @Summary Register a new user +// @Summary Register // @Description Register a new user // @Tags User // @Accept json @@ -42,7 +42,7 @@ func (gs *GState) Register(c *fiber.Ctx) error { // This path should obviously be protected in the future // UserDelete deletes a user from the database // -// @Summary Deletes a user +// @Summary UserDelete // @Description UserDelete deletes a user from the database // @Tags User // @Accept json @@ -125,8 +125,9 @@ func (gs *GState) Login(c *fiber.Ctx) error { // LoginRenew is a simple handler that renews the token // -// @Summary renews the users token +// @Summary LoginRenews // @Description renews the users token +// @Security bererToken // @Tags User // @Accept json // @Produce plain @@ -159,7 +160,7 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { // ListAllUsers is a handler that returns a list of all users in the application database // -// @Summary Lists users +// @Summary ListsAllUsers // @Description lists all users // @Tags User // @Accept json @@ -181,7 +182,7 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } -// @Summary promote user to admin +// @Summary PromoteToAdmin // @Description promote chosen user to admin // @Tags User // @Accept json diff --git a/backend/main.go b/backend/main.go index 9abe995..76c5f99 100644 --- a/backend/main.go +++ b/backend/main.go @@ -23,6 +23,10 @@ import ( // @license.name AGPL // @license.url https://www.gnu.org/licenses/agpl-3.0.html +//@securityDefinitions.apikey bererToken +//@in header +//@name Authorization + // @host localhost:8080 // @BasePath /api @@ -89,7 +93,7 @@ func main() { server.Post("/api/signReport", gs.SignReport) server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) - + server.Get("/api/users/all", gs.ListAllUsers) // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) if err != nil { From d2a8399bde8029b6fbbc8550d69a35dd70e8b901 Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Tue, 19 Mar 2024 00:34:57 +0100 Subject: [PATCH 50/63] minor fix --- frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx b/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx index fc678e2..5127571 100644 --- a/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx +++ b/frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx @@ -6,7 +6,7 @@ import UserProjectListAdmin from "../../Components/UserProjectListAdmin"; function AdminViewUserInfo(): JSX.Element { const content = ( <> - + ); From b8c69fabf5f35c1505725fff97d3b27513e17fbb Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 19 Mar 2024 00:35:27 +0100 Subject: [PATCH 51/63] Remove unused variable and update API call in YourProjectsPage.tsx --- frontend/src/Pages/YourProjectsPage.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index baf18ce..b8034f3 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -11,9 +11,8 @@ function UserProjectPage(): JSX.Element { const [selectedProject, setSelectedProject] = useState(""); const getProjects = async (): Promise => { - const username = localStorage.getItem("username") ?? ""; const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getUserProjects(username, token); + const response = await api.getUserProjects(token); console.log(response); if (response.success) { setProjects(response.data ?? []); From b174ec8922aa7761ba5095f64ea2752aa3f10d06 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Tue, 19 Mar 2024 00:41:30 +0100 Subject: [PATCH 52/63] Rename for clarity and consistensy with TS api --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 76c5f99..e578c52 100644 --- a/backend/main.go +++ b/backend/main.go @@ -83,7 +83,7 @@ func main() { })) // Protected routes (require a valid JWT bearer token authentication header) - server.Post("/api/submitReport", gs.SubmitWeeklyReport) + server.Post("/api/submitWeeklyReport", gs.SubmitWeeklyReport) server.Get("/api/getUserProjects", gs.GetUserProjects) server.Post("/api/loginrenew", gs.LoginRenew) server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches From c03be8c5d91d8c1bb5b15a9292e7a6c575c2629f Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Tue, 19 Mar 2024 00:46:28 +0100 Subject: [PATCH 53/63] Path rename in python testing script --- testing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing.py b/testing.py index 1eea03b..ffadb56 100644 --- a/testing.py +++ b/testing.py @@ -20,7 +20,7 @@ base_url = "http://localhost:8080" registerPath = base_url + "/api/register" loginPath = base_url + "/api/login" addProjectPath = base_url + "/api/project" -submitReportPath = base_url + "/api/submitReport" +submitReportPath = base_url + "/api/submitWeeklyReport" getWeeklyReportPath = base_url + "/api/getWeeklyReport" getProjectPath = base_url + "/api/project" signReportPath = base_url + "/api/signReport" From c072aff9da1c1dfb03d4a2143891a5b94d5f87b0 Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Tue, 19 Mar 2024 01:02:39 +0100 Subject: [PATCH 54/63] added change username button --- frontend/src/Components/AdminUserList.tsx | 0 frontend/src/Components/UserInfoModal.tsx | 10 ++++++++++ frontend/src/Pages/AdminPages/AdminViewUserInfo.tsx | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 frontend/src/Components/AdminUserList.tsx diff --git a/frontend/src/Components/AdminUserList.tsx b/frontend/src/Components/AdminUserList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/Components/UserInfoModal.tsx b/frontend/src/Components/UserInfoModal.tsx index fff6776..21970fb 100644 --- a/frontend/src/Components/UserInfoModal.tsx +++ b/frontend/src/Components/UserInfoModal.tsx @@ -1,3 +1,4 @@ +import { Link } from "react-router-dom"; import Button from "./Button"; import DeleteUser from "./DeleteUser"; import UserProjectListAdmin from "./UserProjectListAdmin"; @@ -30,6 +31,15 @@ function UserInfoModal(props: { }} type="button" /> + +