diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index c8beb1c..57a1969 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -16,7 +16,6 @@ type GlobalState interface { GetUserProjects(c *fiber.Ctx) error // To get all projects SubmitWeeklyReport(c *fiber.Ctx) error GetWeeklyReport(c *fiber.Ctx) error - SignReport(c *fiber.Ctx) error // GetProject(c *fiber.Ctx) error // To get a specific project // UpdateProject(c *fiber.Ctx) error // To update a project // DeleteProject(c *fiber.Ctx) error // To delete a project diff --git a/backend/internal/handlers/handlers_report_related.go b/backend/internal/handlers/handlers_report_related.go index 509bd67..8754afd 100644 --- a/backend/internal/handlers/handlers_report_related.go +++ b/backend/internal/handlers/handlers_report_related.go @@ -37,16 +37,13 @@ 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") 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) week := c.Query("week") - println(week) // Convert week to integer weekInt, err := strconv.Atoi(week) @@ -63,31 +60,3 @@ func (gs *GState) GetWeeklyReport(c *fiber.Ctx) error { // Return the retrieved weekly report return c.JSON(report) } - -func (gs *GState) SignReport(c *fiber.Ctx) error { - // Extract the necessary parameters from the token - user := c.Locals("user").(*jwt.Token) - claims := user.Claims.(jwt.MapClaims) - managerUsername := claims["name"].(string) - - // Extract the report ID and project manager ID from request parameters - reportID, err := strconv.Atoi(c.Params("reportId")) - if err != nil { - return c.Status(400).SendString("Invalid report ID") - } - - // Call the database function to get the project manager ID - managerID, err := gs.Db.GetUserId(managerUsername) - if err != nil { - return c.Status(500).SendString("Failed to get project manager ID") - } - - // Call the database function to sign the weekly report - err = gs.Db.SignWeeklyReport(reportID, managerID) - if err != nil { - return c.Status(500).SendString("Failed to sign the weekly report: " + err.Error()) - } - - // Return success response - return c.Status(200).SendString("Weekly report signed successfully") -} diff --git a/backend/main.go b/backend/main.go index bc33942..7f0f81e 100644 --- a/backend/main.go +++ b/backend/main.go @@ -78,7 +78,6 @@ func main() { server.Post("/api/loginrenew", gs.LoginRenew) server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches server.Post("/api/project", gs.CreateProject) - server.Get("/api/getWeeklyReport", gs.GetWeeklyReport) // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) diff --git a/frontend/src/API/API.test.ts b/frontend/src/API/API.test.ts new file mode 100644 index 0000000..dbae706 --- /dev/null +++ b/frontend/src/API/API.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, test } from "@jest/globals"; +import { api } from "../API/API"; +import { NewUser, NewWeeklyReport } from "../Types/goTypes"; + +describe("API", () => { + test("registerUser", async () => { + const user: NewUser = { + username: "lol", // Add the username property + password: "lol", + }; + const response = await api.registerUser(user); + console.log(response.message); + expect(response.success).toBe(true); + expect(response.data).toHaveProperty("userId"); + }); + + test("createProject", async () => { + const project = { + name: "Project X", + description: "This is a test project", + }; + const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t"; + + const response = await api.createProject(project, token); + console.log(response.message); + expect(response.success).toBe(true); + expect(response.data).toHaveProperty("projectId"); + }); + + test("renewToken", async () => { + const refreshToken = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t"; + + const response = await api.renewToken(refreshToken); + console.log(response.message); + expect(response.success).toBe(true); + expect(response.data).toHaveProperty("accessToken"); + expect(response.data).toHaveProperty("refreshToken"); + }); + + test("getUserProjects", async () => { + const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t"; + const username = "rrgumdzpmc"; + const response = await api.getUserProjects(username, token); + console.log(response.message); + expect(response.success).toBe(true); + expect(response.data).toHaveProperty("projects"); + }); + + test("submitWeeklyReport", async () => { + const report: NewWeeklyReport = { + projectName: "vtmosxssst", + week: 2, + developmentTime: 40, + meetingTime: 5, + adminTime: 2, + ownWorkTime: 10, + studyTime: 12, + testingTime: 41, + }; + const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t"; + + const response = await api.submitWeeklyReport(report, token); + console.log(response.message); + expect(response.success).toBe(true); + expect(response.data).toHaveProperty( + "message", + "Report submitted successfully", + ); + }); + + test("login", async () => { + const user: NewUser = { + username: "rrgumdzpmc", // Add an empty string value for the username property + password: "always_same", + }; + + const response = await api.login(user); + console.log(response.message); + expect(response.success).toBe(true); + expect(response.data).toHaveProperty("accessToken"); + expect(response.data).toHaveProperty("refreshToken"); + }); +}); diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 7a1ccd0..cfd5b61 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -20,32 +20,25 @@ interface API { registerUser(user: NewUser): Promise>; /** Remove a user */ removeUser(username: string, token: string): Promise>; - /** Login */ - login(NewUser: NewUser): Promise>; - /** Renew the token */ - renewToken(token: string): Promise>; /** Create a project */ createProject( project: NewProject, token: string, ): Promise>; + /** Submit a weekly report */ + submitWeeklyReport( + project: NewWeeklyReport, + token: string, + ): Promise>; + /** Renew the token */ + renewToken(token: string): Promise>; /** Gets all the projects of a user*/ getUserProjects( username: string, token: string, ): Promise>; - /** Submit a weekly report */ - submitWeeklyReport( - project: NewWeeklyReport, - token: string, - ): Promise>; - /**Gets a weekly report*/ - getWeeklyReport( - username: string, - projectName: string, - week: string, - token: string, - ): Promise>; + /** Login */ + login(NewUser: NewUser): Promise>; } // Export an instance of the API @@ -61,19 +54,13 @@ export const api: API = { }); if (!response.ok) { - return { - success: false, - message: "Failed to register user: " + response.status, - }; + return { success: false, message: "Failed to register user" }; } else { - // const data = (await response.json()) as User; // The API does not currently return the user - return { success: true }; + const data = (await response.json()) as User; + return { success: true, data }; } } catch (e) { - return { - success: false, - message: "Unknown error while registering user", - }; + return { success: false, message: "Failed to register user" }; } }, @@ -176,9 +163,9 @@ export const api: API = { }, async submitWeeklyReport( - weeklyReport: NewWeeklyReport, + project: NewWeeklyReport, token: string, - ): Promise> { + ): Promise> { try { const response = await fetch("/api/submitWeeklyReport", { method: "POST", @@ -186,7 +173,7 @@ export const api: API = { "Content-Type": "application/json", Authorization: "Bearer " + token, }, - body: JSON.stringify(weeklyReport), + body: JSON.stringify(project), }); if (!response.ok) { @@ -196,7 +183,7 @@ export const api: API = { }; } - const data = (await response.json()) as NewWeeklyReport; + const data = (await response.json()) as Project; return { success: true, data }; } catch (e) { return { @@ -206,33 +193,6 @@ export const api: API = { } }, - async getWeeklyReport( - username: string, - projectName: string, - week: string, - token: string, - ): Promise> { - try { - const response = await fetch("/api/getWeeklyReport", { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify({ username, projectName, week }), - }); - - if (!response.ok) { - return { success: false, message: "Failed to get weekly report" }; - } else { - const data = (await response.json()) as NewWeeklyReport; - return { success: true, data }; - } - } catch (e) { - return { success: false, message: "Failed to get weekly report" }; - } - }, - async login(NewUser: NewUser): Promise> { try { const response = await fetch("/api/login", { diff --git a/frontend/src/Components/AddProject.tsx b/frontend/src/Components/AddProject.tsx deleted file mode 100644 index 45814e3..0000000 --- a/frontend/src/Components/AddProject.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useState } from "react"; -import { APIResponse, api } from "../API/API"; -import { NewProject, Project } from "../Types/goTypes"; -import InputField from "./InputField"; -import Logo from "../assets/Logo.svg"; -import Button from "./Button"; - -/** - * Tries to add a project to the system - * @param props - Project name and description - * @returns {boolean} True if created, false if not - */ -function CreateProject(props: { name: string; description: string }): boolean { - const project: NewProject = { - name: props.name, - description: props.description, - }; - - let created = false; - - api - .createProject(project, localStorage.getItem("accessToken") ?? "") - .then((response: APIResponse) => { - if (response.success) { - created = true; - } else { - console.error(response.message); - } - }) - .catch((error) => { - console.error("An error occurred during creation:", error); - }); - return created; -} - -/** - * Tries to add a project to the system - * @returns {JSX.Element} UI for project adding - */ -function AddProject(): JSX.Element { - const [name, setName] = useState(""); - const [description, setDescription] = useState(""); - - return ( -
-
-
{ - e.preventDefault(); - CreateProject({ name: name, description: description }); - }} - > - TTIME Logo -

- Create a new project -

- { - setName(e.target.value); - }} - /> - { - setDescription(e.target.value); - }} - /> -
-
- -

-
-
- ); -} - -export default AddProject; diff --git a/frontend/src/Components/Header.tsx b/frontend/src/Components/Header.tsx index 7a1e8ba..ba0a939 100644 --- a/frontend/src/Components/Header.tsx +++ b/frontend/src/Components/Header.tsx @@ -5,7 +5,7 @@ function Header({ username }: { username: string }): JSX.Element { const [isOpen, setIsOpen] = useState(false); const handleLogout = (): void => { - localStorage.clear(); + // Add any logout logic here }; return ( diff --git a/frontend/src/Components/LoginCheck.tsx b/frontend/src/Components/LoginCheck.tsx index 786a96c..3658cbf 100644 --- a/frontend/src/Components/LoginCheck.tsx +++ b/frontend/src/Components/LoginCheck.tsx @@ -10,21 +10,17 @@ function LoginCheck(props: { username: string; password: string; setAuthority: Dispatch>; -}): void { +}): number { const user: NewUser = { username: props.username, password: props.password, }; - - localStorage.clear(); - api .login(user) .then((response: APIResponse) => { if (response.success) { if (response.data !== undefined) { const token = response.data; - localStorage.setItem("accessToken", token); //TODO: change so that it checks for user type (admin, user, pm) instead if (token !== "" && props.username === "admin") { props.setAuthority((prevAuth) => { @@ -46,12 +42,14 @@ function LoginCheck(props: { console.error("Token was undefined"); } } else { - console.error("Token could not be fetched/No such user"); + console.error("Token could not be fetched"); } }) .catch((error) => { console.error("An error occurred during login:", error); }); + + return 0; } export default LoginCheck; diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx index d8b2a47..f3d773e 100644 --- a/frontend/src/Components/Register.tsx +++ b/frontend/src/Components/Register.tsx @@ -3,27 +3,40 @@ import { NewUser } from "../Types/goTypes"; import { api } from "../API/API"; import Logo from "../assets/Logo.svg"; import Button from "./Button"; -import InputField from "./InputField"; -import { useNavigate } from "react-router-dom"; + +function InputField(props: { + label: string; + type: string; + value: string; + onChange: (e: React.ChangeEvent) => void; +}): JSX.Element { + return ( +
+ + +
+ ); +} export default function Register(): JSX.Element { - const [username, setUsername] = useState(); - const [password, setPassword] = useState(); - const [errMessage, setErrMessage] = useState(); - - const nav = useNavigate(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); const handleRegister = async (): Promise => { - const newUser: NewUser = { - username: username ?? "", - password: password ?? "", - }; - const response = await api.registerUser(newUser); - if (response.success) { - nav("/"); // Instantly navigate to the login page - } else { - setErrMessage(response.message ?? "Unknown error"); - } + const newUser: NewUser = { username: username, password }; + await api.registerUser(newUser); // TODO: Handle errors }; return ( diff --git a/frontend/src/Components/UserListAdmin.tsx b/frontend/src/Components/UserListAdmin.tsx index b86076a..e25ad5f 100644 --- a/frontend/src/Components/UserListAdmin.tsx +++ b/frontend/src/Components/UserListAdmin.tsx @@ -1,11 +1,11 @@ import { Link } from "react-router-dom"; -import { PublicUser } from "../Types/goTypes"; +import { User } from "../Types/goTypes"; /** * The props for the UserProps component */ interface UserProps { - users: PublicUser[]; + users: User[]; } /** @@ -23,7 +23,7 @@ export function UserListAdmin(props: UserProps): JSX.Element {
    {props.users.map((user) => ( - +
  • {user.username}
  • diff --git a/frontend/src/Pages/AdminPages/AdminAddProject.tsx b/frontend/src/Pages/AdminPages/AdminAddProject.tsx index 6df8851..2922400 100644 --- a/frontend/src/Pages/AdminPages/AdminAddProject.tsx +++ b/frontend/src/Pages/AdminPages/AdminAddProject.tsx @@ -1,13 +1,25 @@ -import AddProject from "../../Components/AddProject"; -import BackButton from "../../Components/BackButton"; import BasicWindow from "../../Components/BasicWindow"; +import Button from "../../Components/Button"; function AdminAddProject(): JSX.Element { - const content = ; + const content = <>; const buttons = ( <> - +