From 74285dc1cfb4d60e95b63bb0dced87855f8e4c87 Mon Sep 17 00:00:00 2001 From: al8763be Date: Tue, 19 Mar 2024 19:45:56 +0100 Subject: [PATCH 01/55] Before fuck up --- frontend/src/API/API.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 8fd66d3..0fc29a0 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -24,6 +24,7 @@ interface API { login(NewUser: NewUser): Promise>; /** Renew the token */ renewToken(token: string): Promise>; + /** Promote user to admin */ /** Create a project */ createProject( project: NewProject, @@ -41,6 +42,10 @@ interface API { week: string, token: string, ): Promise>; + getWeeklyReportsForProject( + projectName: string, + token: string, + ): Promise>; /** Gets all the projects of a user*/ getUserProjects(token: string): Promise>; /** Gets a project from id*/ @@ -232,6 +237,34 @@ export const api: API = { } }, + async getWeeklyReportsForProject(projectName: string, token: string) { + try { + const response = await fetch("/api/getWeeklyReportsForProject", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + body: JSON.stringify({ projectName }), + }); + + if (!response.ok) { + return { + success: false, + message: "Failed to get weekly reports for project", + }; + } else { + const data = (await response.json()) as NewWeeklyReport[]; + return { success: true, data }; + } + } catch (e) { + return { + success: false, + message: "Failed to get weekly reports for project", + }; + } + }, + async login(NewUser: NewUser): Promise> { try { const response = await fetch("/api/login", { From e48bf5d98cdbb468690473a06f0dca364d668a19 Mon Sep 17 00:00:00 2001 From: al8763be Date: Tue, 19 Mar 2024 20:25:26 +0100 Subject: [PATCH 02/55] Added checkIfProjectManager, hope it works --- frontend/src/API/API.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 0fc29a0..a1ecfde 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -20,6 +20,12 @@ interface API { registerUser(user: NewUser): Promise>; /** Remove a user */ removeUser(username: string, token: string): Promise>; + /** Check if user is project manager */ + checkIfProjectManager( + username: string, + projectName: string, + token: string, + ): Promise>; /** Login */ login(NewUser: NewUser): Promise>; /** Renew the token */ @@ -106,6 +112,30 @@ export const api: API = { } }, + async checkIfProjectManager(token: string): Promise> { + try { + const response = await fetch("/api/checkIfProjectManager", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + }); + + if (!response.ok) { + return { + success: false, + message: "Failed to check if project manager", + }; + } else { + const data = (await response.json()) as boolean; + return { success: true, data }; + } + } catch (e) { + return { success: false, message: "fuck" }; + } + }, + async createProject( project: NewProject, token: string, From 0b6edd359ecaa6b19986b520618225c65203223b Mon Sep 17 00:00:00 2001 From: al8763be Date: Tue, 19 Mar 2024 20:29:36 +0100 Subject: [PATCH 03/55] Bumfix for BumCode on checkIfProjectManager --- frontend/src/API/API.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index a1ecfde..fc2367b 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -112,7 +112,11 @@ export const api: API = { } }, - async checkIfProjectManager(token: string): Promise> { + async checkIfProjectManager( + username: string, + projectName: string, + token: string, + ): Promise> { try { const response = await fetch("/api/checkIfProjectManager", { method: "GET", @@ -120,6 +124,7 @@ export const api: API = { "Content-Type": "application/json", Authorization: "Bearer " + token, }, + body: JSON.stringify({ username, projectName }), }); if (!response.ok) { From 3fea87a88a9e58fbb7360b6ef4dbc6b65677710a Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 21:22:49 +0100 Subject: [PATCH 04/55] New component for displaying userprojects --- .../src/Components/DisplayUserProjects.tsx | 40 +++++++++++++++++++ frontend/src/Pages/YourProjectsPage.tsx | 33 +-------------- 2 files changed, 42 insertions(+), 31 deletions(-) create mode 100644 frontend/src/Components/DisplayUserProjects.tsx diff --git a/frontend/src/Components/DisplayUserProjects.tsx b/frontend/src/Components/DisplayUserProjects.tsx new file mode 100644 index 0000000..266f1ce --- /dev/null +++ b/frontend/src/Components/DisplayUserProjects.tsx @@ -0,0 +1,40 @@ +import { useState, useEffect } from "react"; +import { Project } from "../Types/goTypes"; +import { Link } from "react-router-dom"; +import { api } from "../API/API"; + +function DisplayUserProject(): JSX.Element { + const [projects, setProjects] = useState([]); + + const getProjects = async (): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getUserProjects(token); + console.log(response); + if (response.success) { + setProjects(response.data ?? []); + } else { + console.error(response.message); + } + }; + // Call getProjects when the component mounts + useEffect(() => { + void getProjects(); + }, []); + + return ( + <> +

Your Projects

+
+ {projects.map((project, index) => ( + +

+ {project.name} +

+ + ))} +
+ + ); +} + +export default DisplayUserProject; diff --git a/frontend/src/Pages/YourProjectsPage.tsx b/frontend/src/Pages/YourProjectsPage.tsx index b5644c3..c048746 100644 --- a/frontend/src/Pages/YourProjectsPage.tsx +++ b/frontend/src/Pages/YourProjectsPage.tsx @@ -1,39 +1,10 @@ -import { useState, useEffect } from "react"; -import { Project } from "../Types/goTypes"; -import { Link } from "react-router-dom"; import BasicWindow from "../Components/BasicWindow"; -import { api } from "../API/API"; +import DisplayUserProjects from "../Components/DisplayUserProjects"; function UserProjectPage(): JSX.Element { - const [projects, setProjects] = useState([]); - - const getProjects = async (): Promise => { - const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getUserProjects(token); - console.log(response); - if (response.success) { - setProjects(response.data ?? []); - } else { - console.error(response.message); - } - }; - // Call getProjects when the component mounts - useEffect(() => { - void getProjects(); - }, []); - const content = ( <> -

Your Projects

-
- {projects.map((project, index) => ( - -

- {project.name} -

- - ))} -
+ ); From 05b9740c3602c9a26f48efc74aa0a66c9da1b800 Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 21:29:37 +0100 Subject: [PATCH 05/55] Fixed links and changed path in main for pm --- .../src/Pages/ProjectManagerPages/PMProjectPage.tsx | 12 +++++++----- frontend/src/main.tsx | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx index bd4e6ef..15d1d28 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx @@ -1,28 +1,30 @@ -import { Link } from "react-router-dom"; +import { Link, useParams } from "react-router-dom"; import BasicWindow from "../../Components/BasicWindow"; import { JSX } from "react/jsx-runtime"; function PMProjectPage(): JSX.Element { + const { projectName } = useParams(); + const content = ( <>

ProjectNameExample

- +

Your Time Reports

- +

New Time Report

- +

Statistics

- +

Unsigned Time Reports

diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 9970cfa..20ecbcd 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -91,7 +91,7 @@ const router = createBrowserRouter([ element: , }, { - path: "/PMUnsignedReports", + path: "/unsignedReports", element: , }, { From dc6ce4b725a4d1714ce394e2cd4006d3406a7ce3 Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 21:31:20 +0100 Subject: [PATCH 06/55] Additional minor fix --- frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx index 15d1d28..b88ad58 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx @@ -7,7 +7,7 @@ function PMProjectPage(): JSX.Element { const content = ( <> -

ProjectNameExample

+

{projectName}

From d355b556346606a105314a2e0f725d31aa889ac6 Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 21:59:37 +0100 Subject: [PATCH 07/55] Add UserProjectMenu component and refactor UserProjectPage --- frontend/src/Components/UserProjectMenu.tsx | 25 +++++++++++++++++++ .../src/Pages/UserPages/UserProjectPage.tsx | 18 ++----------- 2 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 frontend/src/Components/UserProjectMenu.tsx diff --git a/frontend/src/Components/UserProjectMenu.tsx b/frontend/src/Components/UserProjectMenu.tsx new file mode 100644 index 0000000..986b6e6 --- /dev/null +++ b/frontend/src/Components/UserProjectMenu.tsx @@ -0,0 +1,25 @@ +import { useParams, Link } from "react-router-dom"; +import { JSX } from "react/jsx-runtime"; + +function UserProjectMenu(): JSX.Element { + const { projectName } = useParams(); + + return ( + <> +

{projectName}

+
+ +

+ Your Time Reports +

+ + +

+ New Time Report +

+ +
+ + ); +} +export default UserProjectMenu; diff --git a/frontend/src/Pages/UserPages/UserProjectPage.tsx b/frontend/src/Pages/UserPages/UserProjectPage.tsx index 596c37d..b9578b4 100644 --- a/frontend/src/Pages/UserPages/UserProjectPage.tsx +++ b/frontend/src/Pages/UserPages/UserProjectPage.tsx @@ -1,25 +1,11 @@ -import { Link, useParams } from "react-router-dom"; import BasicWindow from "../../Components/BasicWindow"; import BackButton from "../../Components/BackButton"; +import UserProjectMenu from "../../Components/UserProjectMenu"; function UserProjectPage(): JSX.Element { - const { projectName } = useParams(); - const content = ( <> -

{projectName}

-
- -

- Your Time Reports -

- - -

- New Time Report -

- -
+ ); From 55a2dc7fac2a81b17e2fb4b5d31ff9486e0ce5ba Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 22:03:45 +0100 Subject: [PATCH 08/55] Add PMProjectMenu component and refactor PMProjectPage --- frontend/src/Components/PMProjectMenu.tsx | 34 +++++++++++++++++++ .../ProjectManagerPages/PMProjectPage.tsx | 28 ++------------- 2 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 frontend/src/Components/PMProjectMenu.tsx diff --git a/frontend/src/Components/PMProjectMenu.tsx b/frontend/src/Components/PMProjectMenu.tsx new file mode 100644 index 0000000..ce7c5c5 --- /dev/null +++ b/frontend/src/Components/PMProjectMenu.tsx @@ -0,0 +1,34 @@ +import { Link, useParams } from "react-router-dom"; +import { JSX } from "react/jsx-runtime"; + +function PMProjectMenu(): JSX.Element { + const { projectName } = useParams(); + return ( + <> +

{projectName}

+
+ +

+ Your Time Reports +

+ + +

+ New Time Report +

+ + +

+ Statistics +

+ + +

+ Unsigned Time Reports +

+ +
+ + ); +} +export default PMProjectMenu; diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx index b88ad58..4b0ef05 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx @@ -1,35 +1,11 @@ -import { Link, useParams } from "react-router-dom"; import BasicWindow from "../../Components/BasicWindow"; import { JSX } from "react/jsx-runtime"; +import PMProjectMenu from "../../Components/PMProjectMenu"; function PMProjectPage(): JSX.Element { - const { projectName } = useParams(); - const content = ( <> -

{projectName}

-
- -

- Your Time Reports -

- - -

- New Time Report -

- - -

- Statistics -

- - -

- Unsigned Time Reports -

- -
+ ); From fe89ae0970b5f20bed63de576565678a278ec0fd Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 22:13:06 +0100 Subject: [PATCH 09/55] Added backbutton --- frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx index 4b0ef05..3d550f6 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectPage.tsx @@ -1,6 +1,7 @@ import BasicWindow from "../../Components/BasicWindow"; import { JSX } from "react/jsx-runtime"; import PMProjectMenu from "../../Components/PMProjectMenu"; +import BackButton from "../../Components/BackButton"; function PMProjectPage(): JSX.Element { const content = ( @@ -9,6 +10,12 @@ function PMProjectPage(): JSX.Element { ); - return ; + const buttons = ( + <> + + + ); + + return ; } export default PMProjectPage; From cc9678f375005e5cb2065f1d3e6eb7c89e797bdb Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 22:50:23 +0100 Subject: [PATCH 10/55] Created component for authorized route --- frontend/src/Components/AuthorizedRoute.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 frontend/src/Components/AuthorizedRoute.tsx diff --git a/frontend/src/Components/AuthorizedRoute.tsx b/frontend/src/Components/AuthorizedRoute.tsx new file mode 100644 index 0000000..d9c8c59 --- /dev/null +++ b/frontend/src/Components/AuthorizedRoute.tsx @@ -0,0 +1,18 @@ +import { Navigate } from "react-router-dom"; +import React from "react"; + +interface AuthorizedRouteProps { + children: React.ReactNode; + isAuthorized: boolean; +} + +export function AuthorizedRoute({ + children, + isAuthorized, +}: AuthorizedRouteProps): JSX.Element { + if (!isAuthorized) { + return ; + } + + return children as React.ReactElement; +} From cd2a81e7f2c755f31931e41b3fb7a308b306bd5d Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 22:50:40 +0100 Subject: [PATCH 11/55] Added unauthorizedpage and path in main --- frontend/src/Pages/UnauthorizedPage.tsx | 18 ++++++++++++++++++ frontend/src/main.tsx | 5 +++++ 2 files changed, 23 insertions(+) create mode 100644 frontend/src/Pages/UnauthorizedPage.tsx diff --git a/frontend/src/Pages/UnauthorizedPage.tsx b/frontend/src/Pages/UnauthorizedPage.tsx new file mode 100644 index 0000000..ed21b25 --- /dev/null +++ b/frontend/src/Pages/UnauthorizedPage.tsx @@ -0,0 +1,18 @@ +import Button from "../Components/Button"; + +export default function UnauthorizedPage(): JSX.Element { + return ( + + ); +} \ No newline at end of file diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 20ecbcd..29a67d1 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -30,6 +30,7 @@ import AdminProjectStatistics from "./Pages/AdminPages/AdminProjectStatistics.ts import AdminProjectViewMemberInfo from "./Pages/AdminPages/AdminProjectViewMemberInfo.tsx"; import AdminProjectPage from "./Pages/AdminPages/AdminProjectPage.tsx"; import NotFoundPage from "./Pages/NotFoundPage.tsx"; +import UnauthorizedPage from "./Pages/UnauthorizedPage.tsx"; // This is where the routes are mounted const router = createBrowserRouter([ @@ -146,6 +147,10 @@ const router = createBrowserRouter([ path: "/adminManageUser", element: , }, + { + path: "unauthorized", + element: , + }, ]); // Semi-hacky way to get the root element From 900c1614e9dc6c9621ab826f647249b55a61d23c Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 22:50:57 +0100 Subject: [PATCH 12/55] minor fix --- frontend/src/Pages/UnauthorizedPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/UnauthorizedPage.tsx b/frontend/src/Pages/UnauthorizedPage.tsx index ed21b25..37e3d2c 100644 --- a/frontend/src/Pages/UnauthorizedPage.tsx +++ b/frontend/src/Pages/UnauthorizedPage.tsx @@ -15,4 +15,4 @@ export default function UnauthorizedPage(): JSX.Element {

); -} \ No newline at end of file +} From ffaa6616281dcd4165e575bd9d660b27e4908d8b Mon Sep 17 00:00:00 2001 From: Mattias Date: Tue, 19 Mar 2024 22:51:54 +0100 Subject: [PATCH 13/55] Minor fix --- frontend/src/main.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 29a67d1..ddf7119 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -148,7 +148,7 @@ const router = createBrowserRouter([ element: , }, { - path: "unauthorized", + path: "/unauthorized", element: , }, ]); From 863a14c316eafb0d1d0dbc1d5392e771bc95c659 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 19 Mar 2024 23:44:00 +0100 Subject: [PATCH 14/55] Add WeeklyReport type and update getWeeklyReportsForProject method --- frontend/src/API/API.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index fc2367b..3ebf343 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -4,6 +4,7 @@ import { User, Project, NewProject, + WeeklyReport, } from "../Types/goTypes"; // This type of pattern should be hard to misuse @@ -49,9 +50,10 @@ interface API { token: string, ): Promise>; getWeeklyReportsForProject( + username: string, projectName: string, token: string, - ): Promise>; + ): Promise>; /** Gets all the projects of a user*/ getUserProjects(token: string): Promise>; /** Gets a project from id*/ @@ -272,15 +274,19 @@ export const api: API = { } }, - async getWeeklyReportsForProject(projectName: string, token: string) { + async getWeeklyReportsForProject( + username: string, + projectName: string, + token: string, + ) { try { - const response = await fetch("/api/getWeeklyReportsForProject", { + const response = await fetch("/api/getWeeklyReportsUser", { method: "GET", headers: { "Content-Type": "application/json", Authorization: "Bearer " + token, }, - body: JSON.stringify({ projectName }), + body: JSON.stringify({ username, projectName }), }); if (!response.ok) { @@ -289,13 +295,13 @@ export const api: API = { message: "Failed to get weekly reports for project", }; } else { - const data = (await response.json()) as NewWeeklyReport[]; + const data = (await response.json()) as WeeklyReport[]; return { success: true, data }; } } catch (e) { return { success: false, - message: "Failed to get weekly reports for project", + message: "fuck", }; } }, From b5d3ab7cb73e2a75473770b6166ce94d152bb776 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 19 Mar 2024 23:44:25 +0100 Subject: [PATCH 15/55] Refactor AllTimeReportsInProject component to use API for fetching weekly reports --- .../Components/AllTimeReportsInProject.tsx | 75 ++++--------------- 1 file changed, 16 insertions(+), 59 deletions(-) diff --git a/frontend/src/Components/AllTimeReportsInProject.tsx b/frontend/src/Components/AllTimeReportsInProject.tsx index 067712e..cc2bac4 100644 --- a/frontend/src/Components/AllTimeReportsInProject.tsx +++ b/frontend/src/Components/AllTimeReportsInProject.tsx @@ -1,68 +1,25 @@ import React, { useEffect, useState } from "react"; -import { NewWeeklyReport } from "../Types/goTypes"; +import { WeeklyReport } from "../Types/goTypes"; import { Link, useParams } from "react-router-dom"; +import { api } from "../API/API"; function AllTimeReportsInProject(): JSX.Element { const { projectName } = useParams(); - const [weeklyReports, setWeeklyReports] = useState([]); - - /* const getWeeklyReports = async (): Promise => { - const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getWeeklyReports(token); - console.log(response); - if (response.success) { - setWeeklyReports(response.data ?? []); - } else { - console.error(response.message); - } -}; */ + const [weeklyReports, setWeeklyReports] = useState([]); const getWeeklyReports = async (): Promise => { - const report: NewWeeklyReport[] = [ - { - projectName: projectName ?? "", - week: 10, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 1, - studyTime: 1, - testingTime: 1, - }, - { - projectName: projectName ?? "", - week: 11, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 100, - studyTime: 1, - testingTime: 1, - }, - { - projectName: projectName ?? "", - week: 12, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 1, - studyTime: 1, - testingTime: 1000, - }, - { - projectName: projectName ?? "", - week: 20, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 1, - studyTime: 1, - testingTime: 10000, - }, - // Add more reports as needed - ]; - setWeeklyReports(report); - await Promise.resolve(); + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getWeeklyReportsForProject( + localStorage.getItem("username") ?? "", + projectName ?? "", + token, + ); + console.log(response); + if (response.success) { + setWeeklyReports(response.data ?? []); + } else { + console.error(response.message); + } }; // Call getProjects when the component mounts @@ -96,7 +53,7 @@ function AllTimeReportsInProject(): JSX.Element {

{"Signed: "} - YES + {newWeeklyReport.signedBy ? "YES" : "NO"}

From 033268f4eff1908317f86e93f7c73664860ebe9d Mon Sep 17 00:00:00 2001 From: Davenludd Date: Wed, 20 Mar 2024 08:47:11 +0100 Subject: [PATCH 16/55] Added info to component --- frontend/src/Components/AllTimeReportsInProject.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/Components/AllTimeReportsInProject.tsx b/frontend/src/Components/AllTimeReportsInProject.tsx index cc2bac4..809e6ed 100644 --- a/frontend/src/Components/AllTimeReportsInProject.tsx +++ b/frontend/src/Components/AllTimeReportsInProject.tsx @@ -1,3 +1,6 @@ +//Info: This component is used to display all the time reports for a project. It will display the week number, +//total time spent, and if the report has been signed or not. The user can click on a report to edit it. + import React, { useEffect, useState } from "react"; import { WeeklyReport } from "../Types/goTypes"; import { Link, useParams } from "react-router-dom"; From 1919b7cb990d11f4769e713bcb5189b13f5fb0c7 Mon Sep 17 00:00:00 2001 From: borean Date: Wed, 20 Mar 2024 12:11:05 +0100 Subject: [PATCH 17/55] Added ChangeUserName in db --- backend/internal/database/db.go | 16 +++++++++ backend/internal/handlers/global_state.go | 1 + .../handlers/handlers_project_related.go | 34 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index 680d7e2..8b0c8c4 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -27,6 +27,7 @@ type Database interface { 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 ChangeUserRole(username string, projectname string, role string) error + ChangeUserName(username string, newname string) error GetAllUsersProject(projectname string) ([]UserProjectMember, error) GetAllUsersApplication() ([]string, error) GetProjectsForUser(username string) ([]types.Project, error) @@ -67,6 +68,7 @@ const addWeeklyReport = `WITH UserLookup AS (SELECT id FROM users WHERE username VALUES ((SELECT id FROM ProjectLookup), (SELECT id FROM UserLookup),?, ?, ?, ?, ?, ?, ?);` 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 changeUserName = "UPDATE user SET username = ? WHERE user_id = ?" // WIP const getProjectsForUser = `SELECT p.id, p.name, p.description FROM projects p JOIN user_roles ur ON p.id = ur.project_id @@ -169,6 +171,20 @@ func (d *Db) ChangeUserRole(username string, projectname string, role string) er return err3 } +// ChangeUserRole changes the role of a user within a project. +func (d *Db) ChangeUserName(username string, newname string) error { + // Get the user ID + var userid int + userid, err := d.GetUserId(username) + if err != nil { + panic(err) + } + + // Execute the SQL query to change the user's role + _, err2 := d.Exec(changeUserName, username, userid) + return err2 +} + // GetUserRole retrieves the role of a user within a project. func (d *Db) GetUserRole(username string, projectname string) (string, error) { var role string diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 7a4213b..1934b21 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -38,6 +38,7 @@ type GlobalState interface { 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 + // ProjectNameChange(c * fiber.Ctx) error // WIP } // "Constructor" diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index 7b95c26..055328b 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -93,6 +93,40 @@ func (gs *GState) ProjectRoleChange(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) } +// ProjectRoleChange is a handler that changes a user's role within a project +func (gs *GState) ProjectNameChange(c *fiber.Ctx) error { + + //check token and get username of current user + user := c.Locals("user").(*jwt.Token) + claims := user.Claims.(jwt.MapClaims) + projectManagerUsername := claims["name"].(string) + log.Info(projectManagerUsername) + // Extract the necessary parameters from the request + data := new(types.RoleChange) + if err := c.BodyParser(data); err != nil { + log.Info("error parsing username, project or role") + return c.Status(400).SendString(err.Error()) + } + + // dubble diping and checcking if current user is + + if ismanager, err := gs.Db.IsProjectManager(projectManagerUsername, data.Projectname); err != nil { + log.Warn("Error checking if projectmanager:", err) + return c.Status(500).SendString(err.Error()) + } else if !ismanager { + log.Warn("tried chaning name when not projectmanager:", err) + return c.Status(401).SendString("you can not change name when not projectManager") + } + + // Change the user's role within the project in the database + if err := gs.Db.ChangeUserRole(data.Username, data.Projectname, data.Role); err != nil { + return c.Status(500).SendString(err.Error()) + } + + // Return a success message + return c.SendStatus(fiber.StatusOK) +} + // GetProject retrieves a specific project by its ID func (gs *GState) GetProject(c *fiber.Ctx) error { // Extract the project ID from the request parameters or body From 1b21b2574aa51dc16443792fe084a6dae55fd572 Mon Sep 17 00:00:00 2001 From: Mattias Date: Wed, 20 Mar 2024 12:36:30 +0100 Subject: [PATCH 18/55] Comp for displaying projectmembers and changed path in main --- frontend/src/Components/ProjectMembers.tsx | 99 +++++++++++++++++++ .../ProjectManagerPages/PMProjectMembers.tsx | 13 ++- frontend/src/main.tsx | 8 +- 3 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 frontend/src/Components/ProjectMembers.tsx diff --git a/frontend/src/Components/ProjectMembers.tsx b/frontend/src/Components/ProjectMembers.tsx new file mode 100644 index 0000000..e1f261e --- /dev/null +++ b/frontend/src/Components/ProjectMembers.tsx @@ -0,0 +1,99 @@ +import { useEffect, useState } from "react"; +import { Link, useParams } from "react-router-dom"; + +function ProjectMembers(): JSX.Element { + const { projectName } = useParams(); + const [projectMembers, setProjectMembers] = useState([]); + + // const getProjectMembers = async (): Promise => { + // const token = localStorage.getItem("accessToken") ?? ""; + // const response = await api.getProjectMembers(projectName ?? "", token); + // console.log(response); + // if (response.success) { + // setProjectMembers(response.data ?? []); + // } else { + // console.error(response.message); + // } + // }; + + interface ProjectMember { + username: string; + role: string; + } + + const mockProjectMembers = [ + { + username: "username1", + role: "Project Manager", + }, + { + username: "username2", + role: "System Manager", + }, + { + username: "username3", + role: "Developer", + }, + { + username: "username4", + role: "Tester", + }, + { + username: "username5", + role: "Tester", + }, + { + username: "username6", + role: "Tester", + }, + ]; + + const getProjectMembers = async (): Promise => { + // Use the mock data + setProjectMembers(mockProjectMembers); + + await Promise.resolve(); + }; + + useEffect(() => { + void getProjectMembers(); + }, []); + + return ( + <> +
+ {projectMembers.map((projectMember, index) => ( +

+
+
+

{projectMember.username}

+ Role: +

{projectMember.role}

+
+
+
+ +

+ View Reports +

+ + +

+ Change Role +

+ +
+
+
+

+ ))} +
+ + ); +} + +export default ProjectMembers; diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx index 9fe96cf..11b8636 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx @@ -1,10 +1,19 @@ import BasicWindow from "../../Components/BasicWindow"; import Button from "../../Components/Button"; import BackButton from "../../Components/BackButton"; -import { Link } from "react-router-dom"; +import { Link, useParams } from "react-router-dom"; +import ProjectMembers from "../../Components/ProjectMembers"; function PMProjectMembers(): JSX.Element { - const content = <>; + const { projectName } = useParams(); + const content = ( + <> +

+ All Members In: {projectName}{" "} +

+ + + ); const buttons = ( <> diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 25c7a35..bac2292 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -64,7 +64,7 @@ const router = createBrowserRouter([ element: , }, { - path: "/changeRole", + path: "/changeRole/:projectName/:username", element: , }, { @@ -72,11 +72,11 @@ const router = createBrowserRouter([ element: , }, { - path: "/projectMembers", + path: "/projectMembers/:projectName", element: , }, { - path: "/PMProjectPage", + path: "/PMProjectPage/:projectName", element: , }, { @@ -88,7 +88,7 @@ const router = createBrowserRouter([ element: , }, { - path: "/unsignedReports", + path: "/unsignedReports/:projectName", element: , }, { From 3515a86bbb7dd6062efc9e94dae3c6252a99270b Mon Sep 17 00:00:00 2001 From: borean Date: Wed, 20 Mar 2024 12:50:04 +0100 Subject: [PATCH 19/55] Added ChangeUserName handler, untested and WIP, --- backend/internal/handlers/global_state.go | 2 +- .../handlers/handlers_project_related.go | 34 ----------- .../handlers/handlers_user_related.go | 58 +++++++++++++++---- backend/internal/types/project.go | 5 ++ backend/main.go | 1 + 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 1934b21..4a4b73f 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -38,7 +38,7 @@ type GlobalState interface { 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 - // ProjectNameChange(c * fiber.Ctx) error // WIP + ChangeUserName(c *fiber.Ctx) error // WIP } // "Constructor" diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index 055328b..7b95c26 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -93,40 +93,6 @@ func (gs *GState) ProjectRoleChange(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) } -// ProjectRoleChange is a handler that changes a user's role within a project -func (gs *GState) ProjectNameChange(c *fiber.Ctx) error { - - //check token and get username of current user - user := c.Locals("user").(*jwt.Token) - claims := user.Claims.(jwt.MapClaims) - projectManagerUsername := claims["name"].(string) - log.Info(projectManagerUsername) - // Extract the necessary parameters from the request - data := new(types.RoleChange) - if err := c.BodyParser(data); err != nil { - log.Info("error parsing username, project or role") - return c.Status(400).SendString(err.Error()) - } - - // dubble diping and checcking if current user is - - if ismanager, err := gs.Db.IsProjectManager(projectManagerUsername, data.Projectname); err != nil { - log.Warn("Error checking if projectmanager:", err) - return c.Status(500).SendString(err.Error()) - } else if !ismanager { - log.Warn("tried chaning name when not projectmanager:", err) - return c.Status(401).SendString("you can not change name when not projectManager") - } - - // Change the user's role within the project in the database - if err := gs.Db.ChangeUserRole(data.Username, data.Projectname, data.Role); err != nil { - return c.Status(500).SendString(err.Error()) - } - - // Return a success message - return c.SendStatus(fiber.StatusOK) -} - // GetProject retrieves a specific project by its ID func (gs *GState) GetProject(c *fiber.Ctx) error { // Extract the project ID from the request parameters or body diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 75b8953..862416c 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -105,7 +105,7 @@ func (gs *GState) Login(c *fiber.Ctx) error { if err != nil { log.Info("Error checking admin status:", err) return c.Status(500).SendString(err.Error()) -} + } // Create the Claims claims := jwt.MapClaims{ "name": u.Username, @@ -187,17 +187,17 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } -// @Summary PromoteToAdmin -// @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] +// @Summary PromoteToAdmin +// @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 @@ -219,3 +219,37 @@ func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error { // Return a success message return c.SendStatus(fiber.StatusOK) } + +// Changes a users name in the database +func (gs *GState) ChangeUserName(c *fiber.Ctx) error { + + //check token and get username of current user + user := c.Locals("user").(*jwt.Token) + claims := user.Claims.(jwt.MapClaims) + projectManagerUsername := claims["name"].(string) + log.Info(projectManagerUsername) + // Extract the necessary parameters from the request + data := new(types.NameChange) + if err := c.BodyParser(data); err != nil { + log.Info("error parsing username, project or role") + return c.Status(400).SendString(err.Error()) + } + + // dubble diping and checcking if current user is + + if ismanager, err := gs.Db.IsProjectManager(projectManagerUsername, c.Params(data.Name)); err != nil { + log.Warn("Error checking if projectmanager:", err) + return c.Status(500).SendString(err.Error()) + } else if !ismanager { + log.Warn("tried changing name when not projectmanager:", err) + return c.Status(401).SendString("you can not change name when not projectManager") + } + + // Change the user's name within the project in the database + if err := gs.Db.ChangeUserName(projectManagerUsername, data.Name); err != nil { + return c.Status(500).SendString(err.Error()) + } + + // Return a success message + return c.SendStatus(fiber.StatusOK) +} diff --git a/backend/internal/types/project.go b/backend/internal/types/project.go index c336bcb..6a7c91a 100644 --- a/backend/internal/types/project.go +++ b/backend/internal/types/project.go @@ -19,3 +19,8 @@ type RoleChange struct { Username string `json:"username"` Projectname string `json:"projectname"` } + +type NameChange struct { + ID int `json:"id" db:"id"` + Name string `json:"name" db:"name"` +} diff --git a/backend/main.go b/backend/main.go index d0ccdb1..8a70186 100644 --- a/backend/main.go +++ b/backend/main.go @@ -93,6 +93,7 @@ func main() { server.Get("/api/getWeeklyReport", gs.GetWeeklyReport) server.Post("/api/signReport", gs.SignReport) server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) + server.Put("/api/changeUserName", gs.ChangeUserName) server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) server.Get("/api/users/all", gs.ListAllUsers) server.Get("/api/getWeeklyReportsUser", gs.GetWeeklyReportsUserHandler) From a18ce465de6639b994b22d55d0c28ed5d44da252 Mon Sep 17 00:00:00 2001 From: borean Date: Wed, 20 Mar 2024 13:03:43 +0100 Subject: [PATCH 20/55] Added a handler for getting all users for a specific project, WIP and untested --- backend/internal/handlers/global_state.go | 1 + backend/internal/handlers/handlers_user_related.go | 14 ++++++++++++++ backend/main.go | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 4a4b73f..a3e43ce 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -39,6 +39,7 @@ type GlobalState interface { 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 ChangeUserName(c *fiber.Ctx) error // WIP + GetAllUsersProject(c *fiber.Ctx) error // WIP } // "Constructor" diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 862416c..ea511ac 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -187,6 +187,20 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } +func (gs *GState) GetAllUsersProject(c *fiber.Ctx) error { + // Get all users from a project + projectName := c.Params("projectName") + users, err := gs.Db.GetAllUsersProject(projectName) + if err != nil { + log.Info("Error getting users from project:", 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) +} + // @Summary PromoteToAdmin // @Description promote chosen user to admin // @Tags User diff --git a/backend/main.go b/backend/main.go index 8a70186..888cb51 100644 --- a/backend/main.go +++ b/backend/main.go @@ -88,8 +88,9 @@ func main() { server.Post("/api/loginrenew", gs.LoginRenew) server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches server.Delete("api/project", gs.DeleteProject) // WIP - server.Post("/api/project", gs.CreateProject) + server.Post("/api/project", gs.CreateProject) // WIP server.Get("/api/project/:projectId", gs.GetProject) + server.Get("/api/project/getAllUsers", gs.GetAllUsersProject) server.Get("/api/getWeeklyReport", gs.GetWeeklyReport) server.Post("/api/signReport", gs.SignReport) server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) From d3bb6f49e5d597b7c73816de2cbffd54dd766978 Mon Sep 17 00:00:00 2001 From: Mattias Date: Wed, 20 Mar 2024 13:51:49 +0100 Subject: [PATCH 21/55] New comp changeRoles --- frontend/src/Components/ChangeRoles.tsx | 83 +++++++++++++++++++ .../ProjectManagerPages/PMChangeRole.tsx | 15 ++-- 2 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 frontend/src/Components/ChangeRoles.tsx diff --git a/frontend/src/Components/ChangeRoles.tsx b/frontend/src/Components/ChangeRoles.tsx new file mode 100644 index 0000000..e11d623 --- /dev/null +++ b/frontend/src/Components/ChangeRoles.tsx @@ -0,0 +1,83 @@ +import { useState } from "react"; +import { useParams } from "react-router-dom"; +import Button from "./Button"; + +export default function ChangeRoles(): JSX.Element { + const [selectedRole, setSelectedRole] = useState(""); + const { username } = useParams(); + + const handleRoleChange = ( + event: React.ChangeEvent, + ): void => { + setSelectedRole(event.target.value); + }; + + // const handleSubmit = async (event: React.FormEvent) => { + // event.preventDefault(); + + // const response = await api.changeRole(username, selectedRole, token); + // if (response.success) { + // console.log("Role changed successfully"); + // } else { + // console.error("Failed to change role:", response.message); + // } + // }; + + return ( + <> +

+ Change roll for: {username} +

+
+
+
+ +
+
+ +
+
+ +
+
+
; -} From aa5c4017bb3087d475e4fd85a1f94c7a9d5463c6 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Wed, 20 Mar 2024 13:54:13 +0100 Subject: [PATCH 28/55] Docs/Comments to DisplayUserProjects component --- frontend/src/Components/DisplayUserProjects.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/Components/DisplayUserProjects.tsx b/frontend/src/Components/DisplayUserProjects.tsx index 266f1ce..f4fd782 100644 --- a/frontend/src/Components/DisplayUserProjects.tsx +++ b/frontend/src/Components/DisplayUserProjects.tsx @@ -3,6 +3,10 @@ import { Project } from "../Types/goTypes"; import { Link } from "react-router-dom"; import { api } from "../API/API"; +/** + * Renders a component that displays the projects a user is a part of and links to the projects start-page. + * @returns The JSX element representing the component. + */ function DisplayUserProject(): JSX.Element { const [projects, setProjects] = useState([]); @@ -16,6 +20,7 @@ function DisplayUserProject(): JSX.Element { console.error(response.message); } }; + // Call getProjects when the component mounts useEffect(() => { void getProjects(); From dbeeb609b322d0572abff578e00ac7c0ad44d020 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Wed, 20 Mar 2024 13:54:32 +0100 Subject: [PATCH 29/55] Docs/Comments to GetWeeklyReport component --- frontend/src/Components/EditWeeklyReport.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index 3017204..e824b19 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -4,6 +4,10 @@ import { api } from "../API/API"; import { useNavigate, useParams } from "react-router-dom"; import Button from "./Button"; +/** + * Renders the component for editing a weekly report. + * @returns JSX.Element + */ export default function GetWeeklyReport(): JSX.Element { const [week, setWeek] = useState(0); const [developmentTime, setDevelopmentTime] = useState(0); From cf6c8cd34c779b86ffa07a96427aa66a1be7d1a8 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Wed, 20 Mar 2024 13:54:59 +0100 Subject: [PATCH 30/55] Docs/Comments to Footer component --- frontend/src/Components/Footer.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/Components/Footer.tsx b/frontend/src/Components/Footer.tsx index a3b7469..192926f 100644 --- a/frontend/src/Components/Footer.tsx +++ b/frontend/src/Components/Footer.tsx @@ -1,5 +1,13 @@ +//info: Footer component to display the footer of a page where the buttons are placed import React from "react"; +/** + * Footer component. + * + * @param {Object} props - The component props. + * @param {React.ReactNode} props.children - The children elements to render inside the footer (buttons). + * @returns {JSX.Element} The rendered footer component. + */ function Footer({ children }: { children: React.ReactNode }): JSX.Element { return (