diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index 3732249..f3a7ea0 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" ) @@ -67,37 +68,47 @@ 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") } - 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) 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()) } // Return the project as JSON - println("Returning project: ", project.Name) + log.Info("Returning project: ", project.Name) return c.JSON(project) } 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) } @@ -111,7 +122,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 +130,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..85eb6e2 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" ) @@ -16,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 - println("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") - println(projectName) week := c.Query("week") - println(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) } @@ -69,35 +82,33 @@ type ReportId struct { } func (gs *GState) SignReport(c *fiber.Ctx) error { - println("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) if err := c.BodyParser(rid); err != nil { return err } - println("Signing report for: ", rid.ReportId) - // reportIDInt, err := strconv.Atoi(rid.ReportId) - // println("Signing report for: ", rid.ReportId) - // if err != nil { - // return c.Status(400).SendString("Invalid report ID") - // } + log.Info("Signing report for: ", rid.ReportId) // 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") } - println("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 0f7c047..8f4108c 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) if err := gs.Db.AddUser(u.Username, u.Password); err != nil { + log.Warn("Error adding user:", err) 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") } @@ -46,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") } @@ -61,13 +66,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 logging in:", 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,23 +85,25 @@ 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}) } // 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{ @@ -107,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}) } @@ -117,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) } @@ -132,15 +144,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 16a033c..9abe995 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" @@ -59,6 +60,8 @@ func main() { // Create the server server := fiber.New() + server.Use(logger.New()) + // Mounts the swagger documentation, this is available at /swagger/index.html server.Get("/swagger/*", swagger.HandlerDefault) diff --git a/testing.py b/testing.py index c094dca..1eea03b 100644 --- a/testing.py +++ b/testing.py @@ -28,8 +28,9 @@ 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 @@ -37,7 +38,7 @@ def test_get_user_projects(): 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" @@ -63,6 +64,7 @@ def login(username: string, password: string): print(response.text) return response + # Test function to login def test_login(): response = login(username, "always_same") @@ -70,12 +72,14 @@ def test_login(): print("Login successful") return response.json()["token"] + # Test function to create a new user def test_create_user(): response = register(username, "always_same") assert response.status_code == 200, "Registration failed" print("Registration successful") + # Test function to add a project def test_add_project(): loginResponse = login(username, "always_same") @@ -89,6 +93,7 @@ def test_add_project(): assert response.status_code == 200, "Add project failed" print("Add project successful") + # Test function to submit a report def test_submit_report(): token = login(username, "always_same").json()["token"] @@ -110,40 +115,49 @@ def test_submit_report(): assert response.status_code == 200, "Submit report failed" print("Submit report successful") + # Test function to get a weekly report def test_get_weekly_report(): token = login(username, "always_same").json()["token"] response = requests.get( getWeeklyReportPath, headers={"Authorization": "Bearer " + token}, - params={"username": username, "projectName": projectName , "week": 1} + params={"username": username, "projectName": projectName, "week": 1}, ) print(response.text) assert response.status_code == 200, "Get weekly report failed" + # Tests getting a project by id def test_get_project(): token = login(username, "always_same").json()["token"] response = requests.get( - getProjectPath + "/1", # Assumes that the project with id 1 exists + getProjectPath + "/1", # Assumes that the project with id 1 exists headers={"Authorization": "Bearer " + token}, ) print(response.text) assert response.status_code == 200, "Get project failed" + # Test function to add a user to a project def test_add_user_to_project(): # Log in as a site admin admin_username = randomString() admin_password = "admin_password" - print("Registering with username: ", admin_username, " and password: ", admin_password) + print( + "Registering with username: ", admin_username, " and password: ", admin_password + ) response = requests.post( registerPath, json={"username": admin_username, "password": admin_password} ) print(response.text) admin_token = login(admin_username, admin_password).json()["token"] - response = requests.post(promoteToAdminPath, json={"username": admin_username}, headers={"Authorization": "Bearer " + admin_token}) + response = requests.post( + promoteToAdminPath, + json={"username": admin_username}, + headers={"Authorization": "Bearer " + admin_token}, + ) print(response.text) assert response.status_code == 200, "Promote to site admin failed" print("Admin promoted to site admin successfully") @@ -161,7 +175,8 @@ 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") + print("Add user to project successful") + # Test function to sign a report def test_sign_report(): @@ -172,7 +187,9 @@ def test_sign_report(): # Register an admin admin_username = randomString() admin_password = "admin_password2" - print("Registering with username: ", admin_username, " and password: ", admin_password) + print( + "Registering with username: ", admin_username, " and password: ", admin_password + ) response = requests.post( registerPath, json={"username": admin_username, "password": admin_password} ) @@ -180,18 +197,28 @@ def test_sign_report(): # Log in as the admin admin_token = login(admin_username, admin_password).json()["token"] - response = requests.post(promoteToAdminPath, json={"username": admin_username}, headers={"Authorization": "Bearer " + admin_token}) + response = requests.post( + promoteToAdminPath, + json={"username": admin_username}, + headers={"Authorization": "Bearer " + admin_token}, + ) response = requests.put( addUserToProjectPath, - json={"projectName": projectName, "username": project_manager, "role": "project_manager"}, + json={ + "projectName": projectName, + "username": project_manager, + "role": "project_manager", + }, headers={"Authorization": "Bearer " + admin_token}, - ) + ) assert response.status_code == 200, "Add project manager to project failed" print("Project manager added to project successfully") - + # Log in as the project manager - project_manager_token = login(project_manager, "project_manager_password").json()["token"] + project_manager_token = login(project_manager, "project_manager_password").json()[ + "token" + ] # Submit a report for the project token = login(username, "always_same").json()["token"] @@ -216,7 +243,7 @@ def test_sign_report(): response = requests.get( getWeeklyReportPath, headers={"Authorization": "Bearer " + token}, - params={"username": username, "projectName": projectName , "week": 1} + params={"username": username, "projectName": projectName, "week": 1}, ) print(response.text) report_id = response.json()["reportId"] @@ -234,7 +261,7 @@ def test_sign_report(): response = requests.get( getWeeklyReportPath, headers={"Authorization": "Bearer " + token}, - params={"username": username, "projectName": projectName , "week": 1} + params={"username": username, "projectName": projectName, "week": 1}, ) print(response.text)