diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index 5cbb13f..7f4a89c 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -2,7 +2,6 @@ package database import ( "embed" - "errors" "path/filepath" "ttime/internal/types" @@ -31,7 +30,6 @@ type Database interface { GetProject(projectId int) (types.Project, error) GetUserRole(username string, projectname string) (string, error) GetWeeklyReport(username string, projectName string, week int) (types.WeeklyReport, error) - SignWeeklyReport(reportId int, projectManagerId int) error } // This struct is a wrapper type that holds the database connection @@ -272,8 +270,7 @@ func (d *Db) GetWeeklyReport(username string, projectName string, week int) (typ admin_time, own_work_time, study_time, - testing_time, - signed_by + testing_time FROM weekly_reports WHERE @@ -285,34 +282,6 @@ func (d *Db) GetWeeklyReport(username string, projectName string, week int) (typ return report, err } -// SignWeeklyReport signs a weekly report by updating the signed_by field -// with the provided project manager's ID, but only if the project manager -// is in the same project as the report -func (d *Db) SignWeeklyReport(reportId int, projectManagerId int) error { - // Retrieve the project ID associated with the report - var reportProjectID int - err := d.Get(&reportProjectID, "SELECT project_id FROM weekly_reports WHERE report_id = ?", reportId) - if err != nil { - return err - } - - // Retrieve the project ID associated with the project manager - var managerProjectID int - err = d.Get(&managerProjectID, "SELECT project_id FROM user_roles WHERE user_id = ? AND p_role = 'project_manager'", projectManagerId) - if err != nil { - return err - } - - // Check if the project manager is in the same project as the report - if reportProjectID != managerProjectID { - return errors.New("project manager doesn't have permission to sign the report") - } - - // Update the signed_by field of the specified report - _, err = d.Exec("UPDATE weekly_reports SET signed_by = ? WHERE report_id = ?", projectManagerId, reportId) - return err -} - // Reads a directory of migration files and applies them to the database. // This will eventually be used on an embedded directory func (d *Db) Migrate() error { diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go index 09de45b..f791066 100644 --- a/backend/internal/database/db_test.go +++ b/backend/internal/database/db_test.go @@ -1,7 +1,6 @@ package database import ( - "fmt" "testing" ) @@ -411,128 +410,3 @@ func TestGetWeeklyReport(t *testing.T) { } // Check other fields similarly } - -func TestSignWeeklyReport(t *testing.T) { - db, err := setupState() - if err != nil { - t.Error("setupState failed:", err) - } - - // Add project manager - err = db.AddUser("projectManager", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - // Add a regular user - err = db.AddUser("testuser", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - // Add project - err = db.AddProject("testproject", "description", "projectManager") - if err != nil { - t.Error("AddProject failed:", err) - } - - // Add both regular users as members to the project - err = db.AddUserToProject("testuser", "testproject", "member") - if err != nil { - t.Error("AddUserToProject failed:", err) - } - - err = db.AddUserToProject("projectManager", "testproject", "project_manager") - if err != nil { - t.Error("AddUserToProject failed:", err) - } - - // Add a weekly report for one of the regular users - err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1) - if err != nil { - t.Error("AddWeeklyReport failed:", err) - } - - // Retrieve the added report - report, err := db.GetWeeklyReport("testuser", "testproject", 1) - if err != nil { - t.Error("GetWeeklyReport failed:", err) - } - - // Print project manager's ID - projectManagerID, err := db.GetUserId("projectManager") - if err != nil { - t.Error("GetUserId failed:", err) - } - fmt.Println("Project Manager's ID:", projectManagerID) - - // Sign the report with the project manager - err = db.SignWeeklyReport(report.ReportId, projectManagerID) - if err != nil { - t.Error("SignWeeklyReport failed:", err) - } - - // Retrieve the report again to check if it's signed - signedReport, err := db.GetWeeklyReport("testuser", "testproject", 1) - if err != nil { - t.Error("GetWeeklyReport failed:", err) - } - - // Ensure the report is signed by the project manager - if *signedReport.SignedBy != projectManagerID { - t.Errorf("Expected SignedBy to be %d, got %d", projectManagerID, *signedReport.SignedBy) - } -} - -func TestSignWeeklyReportByAnotherProjectManager(t *testing.T) { - db, err := setupState() - if err != nil { - t.Error("setupState failed:", err) - } - - // Add project manager - err = db.AddUser("projectManager", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - // Add a regular user - err = db.AddUser("testuser", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - // Add project - err = db.AddProject("testproject", "description", "projectManager") - if err != nil { - t.Error("AddProject failed:", err) - } - - // Add the regular user as a member to the project - err = db.AddUserToProject("testuser", "testproject", "member") - if err != nil { - t.Error("AddUserToProject failed:", err) - } - - // Add a weekly report for the regular user - err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1) - if err != nil { - t.Error("AddWeeklyReport failed:", err) - } - - // Retrieve the added report - report, err := db.GetWeeklyReport("testuser", "testproject", 1) - if err != nil { - t.Error("GetWeeklyReport failed:", err) - } - - anotherManagerID, err := db.GetUserId("projectManager") - if err != nil { - t.Error("GetUserId failed:", err) - } - - err = db.SignWeeklyReport(report.ReportId, anotherManagerID) - if err == nil { - t.Error("Expected SignWeeklyReport to fail with a project manager who is not in the project, but it didn't") - } -} 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/internal/types/WeeklyReport.go b/backend/internal/types/WeeklyReport.go index 299395a..b704cc8 100644 --- a/backend/internal/types/WeeklyReport.go +++ b/backend/internal/types/WeeklyReport.go @@ -41,6 +41,4 @@ type WeeklyReport struct { StudyTime int `json:"studyTime" db:"study_time"` // Total time spent on testing TestingTime int `json:"testingTime" db:"testing_time"` - // The project manager who signed it - SignedBy *int `json:"signedBy" db:"signed_by"` } 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.ts b/frontend/src/API/API.ts index ac0f531..248ad37 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -1,13 +1,8 @@ -import { - NewWeeklyReport, - NewUser, - User, - Project, - NewProject, -} from "../Types/goTypes"; +import { NewProject, Project } from "../Types/Project"; +import { NewUser, User } from "../Types/Users"; // This type of pattern should be hard to misuse -export interface APIResponse { +interface APIResponse { success: boolean; message?: string; data?: T; @@ -20,32 +15,13 @@ 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>; - /**Gets a weekly report*/ - getWeeklyReport( - username: string, - projectName: string, - week: string, - token: string, - ): Promise>; - /** Gets all the projects of a user*/ - getUserProjects( - username: string, - token: string, - ): Promise>; + /** Renew the token */ + renewToken(token: string): Promise>; } // Export an instance of the API @@ -61,19 +37,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" }; } }, @@ -147,110 +117,4 @@ export const api: API = { return { success: false, message: "Failed to renew token" }; } }, - - async getUserProjects(token: string): Promise> { - try { - const response = await fetch("/api/getUserProjects", { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - }); - - if (!response.ok) { - return Promise.resolve({ - success: false, - message: "Failed to get user projects", - }); - } else { - const data = (await response.json()) as Project[]; - return Promise.resolve({ success: true, data }); - } - } catch (e) { - return Promise.resolve({ - success: false, - message: "Failed to get user projects", - }); - } - }, - - async submitWeeklyReport( - weeklyReport: NewWeeklyReport, - token: string, - ): Promise> { - try { - const response = await fetch("/api/submitWeeklyReport", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify(weeklyReport), - }); - - if (!response.ok) { - return { - success: false, - message: "Failed to submit weekly report", - }; - } - - const data = (await response.json()) as NewWeeklyReport; - return { success: true, data }; - } catch (e) { - return { - success: false, - message: "Failed to submit weekly report", - }; - } - }, - - 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", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(NewUser), - }); - - if (!response.ok) { - return { success: false, message: "Failed to login" }; - } else { - const data = (await response.json()) as { token: string }; // Update the type of 'data' - return { success: true, data: data.token }; - } - } catch (e) { - return Promise.resolve({ success: false, message: "Failed to login" }); - } - }, }; diff --git a/frontend/src/Components/BackButton.tsx b/frontend/src/Components/BackButton.tsx deleted file mode 100644 index 7a1ac81..0000000 --- a/frontend/src/Components/BackButton.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { useNavigate } from "react-router-dom"; - -function BackButton(): JSX.Element { - const navigate = useNavigate(); - const goBack = (): void => { - navigate(-1); - }; - return ( - - ); -} - -export default BackButton; diff --git a/frontend/src/Components/BackgroundAnimation.tsx b/frontend/src/Components/BackgroundAnimation.tsx deleted file mode 100644 index 5f402c0..0000000 --- a/frontend/src/Components/BackgroundAnimation.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useEffect } from "react"; - -const BackgroundAnimation = (): JSX.Element => { - useEffect(() => { - const images = [ - "src/assets/1.jpg", - "src/assets/2.jpg", - "src/assets/3.jpg", - "src/assets/4.jpg", - ]; - - // Pre-load images - for (const i of images) { - console.log(i); - } - - // Start animation - document.body.style.animation = "backgroundTransition 30s infinite"; - }, []); - - return <>; -}; - -export default BackgroundAnimation; diff --git a/frontend/src/Components/InputField.tsx b/frontend/src/Components/InputField.tsx deleted file mode 100644 index 639b4ca..0000000 --- a/frontend/src/Components/InputField.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * A customizable input field - * @param props - Settings for the field - * @returns {JSX.Element} The input field - * @example - * { - * setExample(e.target.value); - * }} - * value={example} - * /> - */ -function InputField(props: { - label: string; - type: string; - value: string; - onChange: (e: React.ChangeEvent) => void; -}): JSX.Element { - return ( -
- - -
- ); -} - -export default InputField; diff --git a/frontend/src/Components/LoginCheck.tsx b/frontend/src/Components/LoginCheck.tsx deleted file mode 100644 index 3658cbf..0000000 --- a/frontend/src/Components/LoginCheck.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { NewUser } from "../Types/goTypes"; -import { api, APIResponse } from "../API/API"; -import { Dispatch, SetStateAction } from "react"; - -/* - * Checks if user is in database with api.login and then sets proper authority level - * TODO: change so that it checks for user type (admin, user, pm) somehow instead - **/ -function LoginCheck(props: { - username: string; - password: string; - setAuthority: Dispatch>; -}): number { - const user: NewUser = { - username: props.username, - password: props.password, - }; - api - .login(user) - .then((response: APIResponse) => { - if (response.success) { - if (response.data !== undefined) { - const token = response.data; - //TODO: change so that it checks for user type (admin, user, pm) instead - if (token !== "" && props.username === "admin") { - props.setAuthority((prevAuth) => { - prevAuth = 1; - return prevAuth; - }); - } else if (token !== "" && props.username === "pm") { - props.setAuthority((prevAuth) => { - prevAuth = 2; - return prevAuth; - }); - } else if (token !== "" && props.username === "user") { - props.setAuthority((prevAuth) => { - prevAuth = 3; - return prevAuth; - }); - } - } else { - console.error("Token was undefined"); - } - } else { - 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/LoginField.tsx b/frontend/src/Components/LoginField.tsx deleted file mode 100644 index d7768c0..0000000 --- a/frontend/src/Components/LoginField.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Dispatch, FormEventHandler, SetStateAction } from "react"; -import Button from "./Button"; -import InputField from "./InputField"; - -/** - * A login field complete with input fields - * and a button for submitting the information - * @param props - Settings - * @returns {JSX.Element} A login component - * @example - * - */ -function Login(props: { - handleSubmit: FormEventHandler; - setUsername: Dispatch>; - setPassword: Dispatch>; - username: string; - password: string; -}): JSX.Element { - return ( -
- { - props.setUsername(e.target.value); - }} - value={props.username} - /> - { - props.setPassword(e.target.value); - }} - value={props.password} - /> -