From 2b41085865c7a1809bb598f362e65860bafd3456 Mon Sep 17 00:00:00 2001 From: dDogge Date: Tue, 19 Mar 2024 19:04:45 +0100 Subject: [PATCH 1/5] Added GetWeeklyReportsUser function and handler, also corresponding tests to both GetWeeklyReportsUser and handler added --- backend/internal/database/db.go | 31 +++++++++++++++ backend/internal/database/db_test.go | 39 +++++++++++++++++++ backend/internal/handlers/global_state.go | 1 + .../handlers/handlers_report_related.go | 19 +++++++++ backend/internal/types/WeeklyReport.go | 21 ++++++++++ backend/main.go | 2 + testing.py | 18 +++++++++ 7 files changed, 131 insertions(+) diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index bc6e1e8..574557a 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -32,6 +32,7 @@ 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) + GetWeeklyReportsUser(username string, projectname string) ([]types.WeeklyReportList, error) SignWeeklyReport(reportId int, projectManagerId int) error IsSiteAdmin(username string) (bool, error) } @@ -402,6 +403,36 @@ func (d *Db) Migrate() error { return nil } +// GetWeeklyReportsUser retrieves weekly reports for a specific user and project. +func (d *Db) GetWeeklyReportsUser(username string, projectName string) ([]types.WeeklyReportList, error) { + query := ` + SELECT + wr.week, + wr.development_time, + wr.meeting_time, + wr.admin_time, + wr.own_work_time, + wr.study_time, + wr.testing_time, + wr.signed_by + FROM + weekly_reports wr + INNER JOIN + users u ON wr.user_id = u.id + INNER JOIN + projects p ON wr.project_id = p.id + WHERE + u.username = ? AND p.name = ? + ` + + var reports []types.WeeklyReportList + if err := d.Select(&reports, query, username, projectName); err != nil { + return nil, err + } + + return reports, nil +} + // MigrateSampleData applies sample data to the database. func (d *Db) MigrateSampleData() error { // Insert sample data diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go index a7f3878..a6009cf 100644 --- a/backend/internal/database/db_test.go +++ b/backend/internal/database/db_test.go @@ -566,3 +566,42 @@ func TestGetProject(t *testing.T) { t.Errorf("Expected Name to be testproject, got %s", project.Name) } } + +func TestGetWeeklyReportsUser(t *testing.T) { + db, err := setupState() + if err != nil { + t.Error("setupState failed:", err) + } + + err = db.AddUser("testuser", "password") + if err != nil { + t.Error("AddUser failed:", err) + } + + err = db.AddProject("testproject", "description", "testuser") + if err != nil { + t.Error("AddProject failed:", err) + } + + err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1) + if err != nil { + t.Error("AddWeeklyReport failed:", err) + } + + err = db.AddWeeklyReport("testproject", "testuser", 2, 1, 1, 1, 1, 1, 1) + if err != nil { + t.Error("AddWeeklyReport failed:", err) + } + + reports, err := db.GetWeeklyReportsUser("testuser", "testproject") + if err != nil { + t.Error("GetWeeklyReportsUser failed:", err) + } + + // Check if the retrieved reports match the expected values + if len(reports) != 2 { + t.Errorf("Expected 1 report, got %d", len(reports)) + } + + // You can add further checks here if needed +} diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 932451d..0d041b0 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -20,6 +20,7 @@ type GlobalState interface { GetProject(c *fiber.Ctx) error AddUserToProjectHandler(c *fiber.Ctx) error PromoteToAdmin(c *fiber.Ctx) error + GetWeeklyReportsUserHandler(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 85eb6e2..b745400 100644 --- a/backend/internal/handlers/handlers_report_related.go +++ b/backend/internal/handlers/handlers_report_related.go @@ -114,3 +114,22 @@ func (gs *GState) SignReport(c *fiber.Ctx) error { return c.Status(200).SendString("Weekly report signed successfully") } + +// GetWeeklyReportsUserHandler retrieves all weekly reports for a user in a specific project +func (gs *GState) GetWeeklyReportsUserHandler(c *fiber.Ctx) error { + // Extract necessary parameters from the request + username := c.Params("username") + projectName := c.Params("projectName") + + // Retrieve weekly reports for the user in the project from the database + reports, err := gs.Db.GetWeeklyReportsUser(username, projectName) + if err != nil { + log.Info("Error getting weekly reports for user:", err) + return c.Status(500).SendString(err.Error()) + } + + log.Info("Returning weekly reports for user:", username, "in project:", projectName) + + // Return the list of reports as JSON + return c.JSON(reports) +} diff --git a/backend/internal/types/WeeklyReport.go b/backend/internal/types/WeeklyReport.go index 299395a..8d22b6a 100644 --- a/backend/internal/types/WeeklyReport.go +++ b/backend/internal/types/WeeklyReport.go @@ -20,6 +20,27 @@ type NewWeeklyReport struct { TestingTime int `json:"testingTime"` } +type WeeklyReportList struct { + // The name of the project, as it appears in the database + ProjectName string `json:"projectName" db:"project_name"` + // The week number + Week int `json:"week" db:"week"` + // Total time spent on development + DevelopmentTime int `json:"developmentTime" db:"development_time"` + // Total time spent in meetings + MeetingTime int `json:"meetingTime" db:"meeting_time"` + // Total time spent on administrative tasks + AdminTime int `json:"adminTime" db:"admin_time"` + // Total time spent on personal projects + OwnWorkTime int `json:"ownWorkTime" db:"own_work_time"` + // Total time spent on studying + 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"` +} + type WeeklyReport struct { // The ID of the report ReportId int `json:"reportId" db:"report_id"` diff --git a/backend/main.go b/backend/main.go index e578c52..900e1bd 100644 --- a/backend/main.go +++ b/backend/main.go @@ -94,6 +94,8 @@ func main() { server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) server.Get("/api/users/all", gs.ListAllUsers) + server.Get("/api/getWeeklyReportsUser", gs.GetWeeklyReportsUserHandler) + // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) if err != nil { diff --git a/testing.py b/testing.py index a3de715..6b262fe 100644 --- a/testing.py +++ b/testing.py @@ -37,6 +37,7 @@ signReportPath = base_url + "/api/signReport" addUserToProjectPath = base_url + "/api/addUserToProject" promoteToAdminPath = base_url + "/api/promoteToAdmin" getUserProjectsPath = base_url + "/api/getUserProjects" +getWeeklyReportsUserPath = base_url + "/api/getWeeklyReportsUser" def test_get_user_projects(): @@ -275,6 +276,22 @@ def test_sign_report(): dprint(response.text) gprint("test_sign_report successful") +# Test function to get weekly reports for a user in a project +def test_get_weekly_reports_user(): + # Log in as the user + token = login(username, "always_same").json()["token"] + + # Get weekly reports for the user in the project + response = requests.get( + getWeeklyReportsUserPath, + headers={"Authorization": "Bearer " + token}, + params={"username": username, "projectName": projectName}, + ) + + dprint(response.text) + assert response.status_code == 200, "Get weekly reports for user failed" + gprint("test_get_weekly_reports_user successful") + if __name__ == "__main__": test_get_user_projects() @@ -286,3 +303,4 @@ if __name__ == "__main__": test_get_project() test_sign_report() test_add_user_to_project() + test_get_weekly_reports_user() From 5778d6e892435db5eafb59d7117cad9681220aa3 Mon Sep 17 00:00:00 2001 From: dDogge Date: Tue, 19 Mar 2024 19:14:55 +0100 Subject: [PATCH 2/5] Added isProjectManager function to db.go and corresponding test to db_test.go --- backend/internal/database/db.go | 22 +++++++++++ backend/internal/database/db_test.go | 56 +++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index 574557a..842ffbd 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -35,6 +35,7 @@ type Database interface { GetWeeklyReportsUser(username string, projectname string) ([]types.WeeklyReportList, error) SignWeeklyReport(reportId int, projectManagerId int) error IsSiteAdmin(username string) (bool, error) + IsProjectManager(username string, projectname string) (bool, error) } // This struct is a wrapper type that holds the database connection @@ -433,6 +434,27 @@ func (d *Db) GetWeeklyReportsUser(username string, projectName string) ([]types. return reports, nil } +// IsProjectManager checks if a given username is a project manager for the specified project +func (d *Db) IsProjectManager(username string, projectname string) (bool, error) { + // Define the SQL query to check if the user is a project manager for the project + query := ` + SELECT COUNT(*) FROM user_roles + JOIN users ON user_roles.user_id = users.id + JOIN projects ON user_roles.project_id = projects.id + WHERE users.username = ? AND projects.name = ? AND user_roles.p_role = 'project_manager' + ` + + // Execute the query + var count int + err := d.Get(&count, query, username, projectname) + if err != nil { + return false, err + } + + // If count is greater than 0, the user is a project manager for the project + return count > 0, nil +} + // MigrateSampleData applies sample data to the database. func (d *Db) MigrateSampleData() error { // Insert sample data diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go index a6009cf..2448e7e 100644 --- a/backend/internal/database/db_test.go +++ b/backend/internal/database/db_test.go @@ -602,6 +602,58 @@ func TestGetWeeklyReportsUser(t *testing.T) { if len(reports) != 2 { t.Errorf("Expected 1 report, got %d", len(reports)) } - - // You can add further checks here if needed +} + +func TestIsProjectManager(t *testing.T) { + db, err := setupState() + if err != nil { + t.Error("setupState failed:", err) + } + + // Add a 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) + } + + // Check if the regular user is not a project manager + isManager, err := db.IsProjectManager("testuser", "testproject") + if err != nil { + t.Error("IsProjectManager failed:", err) + } + if isManager { + t.Error("Expected testuser not to be a project manager, but it is.") + } + + // Check if the project manager is indeed a project manager + isManager, err = db.IsProjectManager("projectManager", "testproject") + if err != nil { + t.Error("IsProjectManager failed:", err) + } + if !isManager { + t.Error("Expected projectManager to be a project manager, but it's not.") + } } From ce4cf788ae2beaf148825b0753992cd85498f81f Mon Sep 17 00:00:00 2001 From: dDogge Date: Tue, 19 Mar 2024 19:30:01 +0100 Subject: [PATCH 3/5] Added handler and corresponding test for the IsProjectManager function --- backend/internal/handlers/global_state.go | 1 + .../handlers/handlers_project_related.go | 17 ++++++++++++++++ backend/main.go | 1 + testing.py | 20 +++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 0d041b0..5d01368 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -21,6 +21,7 @@ type GlobalState interface { AddUserToProjectHandler(c *fiber.Ctx) error PromoteToAdmin(c *fiber.Ctx) error GetWeeklyReportsUserHandler(c *fiber.Ctx) error + IsProjectManagerHandler(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_project_related.go b/backend/internal/handlers/handlers_project_related.go index f3a7ea0..df9f3e0 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -154,3 +154,20 @@ func (gs *GState) AddUserToProjectHandler(c *fiber.Ctx) error { log.Info("User added to project successfully:", requestData.Username) return c.SendStatus(fiber.StatusOK) } + +// IsProjectManagerHandler is a handler that checks if a user is a project manager for a given project +func (gs *GState) IsProjectManagerHandler(c *fiber.Ctx) error { + // Extract necessary parameters from the request query string + username := c.Query("username") + projectName := c.Query("projectName") + + // Check if the user is a project manager for the specified project + isManager, err := gs.Db.IsProjectManager(username, projectName) + if err != nil { + log.Info("Error checking project manager status:", err) + return c.Status(500).SendString(err.Error()) + } + + // Return the result as JSON + return c.JSON(map[string]bool{"isProjectManager": isManager}) +} diff --git a/backend/main.go b/backend/main.go index 900e1bd..abdf0db 100644 --- a/backend/main.go +++ b/backend/main.go @@ -95,6 +95,7 @@ func main() { server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) server.Get("/api/users/all", gs.ListAllUsers) server.Get("/api/getWeeklyReportsUser", gs.GetWeeklyReportsUserHandler) + server.Get("api/checkIfProjectManager", gs.IsProjectManagerHandler) // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) diff --git a/testing.py b/testing.py index 6b262fe..670abcd 100644 --- a/testing.py +++ b/testing.py @@ -38,6 +38,7 @@ addUserToProjectPath = base_url + "/api/addUserToProject" promoteToAdminPath = base_url + "/api/promoteToAdmin" getUserProjectsPath = base_url + "/api/getUserProjects" getWeeklyReportsUserPath = base_url + "/api/getWeeklyReportsUser" +checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager" def test_get_user_projects(): @@ -292,6 +293,24 @@ def test_get_weekly_reports_user(): assert response.status_code == 200, "Get weekly reports for user failed" gprint("test_get_weekly_reports_user successful") +# Test function to check if a user is a project manager +def test_check_if_project_manager(): + # Log in as the user + token = login(username, "always_same").json()["token"] + + # Check if the user is a project manager for the project + response = requests.get( + checkIfProjectManagerPath, + headers={"Authorization": "Bearer " + token}, + params={"username": username, "projectName": projectName}, + ) + + dprint(response.text) + assert response.status_code == 200, "Check if project manager failed" + gprint("test_check_if_project_manager successful") + + + if __name__ == "__main__": test_get_user_projects() @@ -304,3 +323,4 @@ if __name__ == "__main__": test_sign_report() test_add_user_to_project() test_get_weekly_reports_user() + test_check_if_project_manager() From cb44954477c975d77e5f05588e13f4253acaa47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20H=C3=B6gbom=20Aronson?= Date: Tue, 19 Mar 2024 23:08:14 +0100 Subject: [PATCH 4/5] -added auth for rolechange, endpoint and test --- .../handlers/handlers_project_related.go | 26 +++++++++++++--- backend/internal/types/project.go | 6 ++++ backend/main.go | 2 +- testing.py | 30 +++++++++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index df9f3e0..2ab5869 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -49,13 +49,31 @@ func (gs *GState) GetUserProjects(c *fiber.Ctx) error { // ProjectRoleChange is a handler that changes a user's role within a project func (gs *GState) ProjectRoleChange(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 - username := c.Params("username") - projectName := c.Params("projectName") - role := c.Params("role") + 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 role when not projectmanager:", err) + return c.Status(401).SendString("you can not change role when not projectManager") + } // Change the user's role within the project in the database - if err := gs.Db.ChangeUserRole(username, projectName, role); err != nil { + if err := gs.Db.ChangeUserRole(data.Username, data.Projectname, data.Role); err != nil { return c.Status(500).SendString(err.Error()) } diff --git a/backend/internal/types/project.go b/backend/internal/types/project.go index 7e1747f..c336bcb 100644 --- a/backend/internal/types/project.go +++ b/backend/internal/types/project.go @@ -13,3 +13,9 @@ type NewProject struct { Name string `json:"name"` Description string `json:"description"` } + +type RoleChange struct { + Role string `json:"role" tstype:"'project_manager' | 'user'"` + Username string `json:"username"` + Projectname string `json:"projectname"` +} diff --git a/backend/main.go b/backend/main.go index abdf0db..60027fd 100644 --- a/backend/main.go +++ b/backend/main.go @@ -96,7 +96,7 @@ func main() { server.Get("/api/users/all", gs.ListAllUsers) server.Get("/api/getWeeklyReportsUser", gs.GetWeeklyReportsUserHandler) server.Get("api/checkIfProjectManager", gs.IsProjectManagerHandler) - + server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange) // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) if err != nil { diff --git a/testing.py b/testing.py index 670abcd..0b803f5 100644 --- a/testing.py +++ b/testing.py @@ -39,7 +39,36 @@ promoteToAdminPath = base_url + "/api/promoteToAdmin" getUserProjectsPath = base_url + "/api/getUserProjects" getWeeklyReportsUserPath = base_url + "/api/getWeeklyReportsUser" checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager" +ProjectRoleChangePath = base_url + "/api/ProjectRoleChange" +#ta bort auth i handlern för att få testet att gå igenom +def test_ProjectRoleChange(): + dprint("Testing ProjectRoleChange") + project_manager = randomString() + register(project_manager, "project_manager_password") + + token = login(project_manager, "project_manager_password").json()[ + "token" + ] + response = requests.post( + addProjectPath, + json={"name": projectName, "description": "This is a project"}, + headers={"Authorization": "Bearer " + token}, + ) + response = requests.post( + ProjectRoleChangePath, + headers={"Authorization": "Bearer " + token}, + json={ + "username": username, + "projectName": projectName, + "week": 1 + }, + ) + if response.status_code != 200: + print("auth not working, för att man inte kan få tag på pm token atm, för att få igenom det så ta bort auth i handler") + + assert response.status_code == 200, "change role successfully" + def test_get_user_projects(): @@ -324,3 +353,4 @@ if __name__ == "__main__": test_add_user_to_project() test_get_weekly_reports_user() test_check_if_project_manager() + test_ProjectRoleChange() From b7b831d869b2dc0f0f314339853209821f139b85 Mon Sep 17 00:00:00 2001 From: Melker Date: Tue, 19 Mar 2024 23:54:54 +0100 Subject: [PATCH 5/5] Lagt till om Admin=True/false --- backend/internal/handlers/handlers_user_related.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 96fddb7..75b8953 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -101,10 +101,15 @@ func (gs *GState) Login(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusUnauthorized) } + isAdmin, err := gs.Db.IsSiteAdmin(u.Username) + 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, - "admin": false, + "admin": isAdmin, "exp": time.Now().Add(time.Hour * 72).Unix(), }