diff --git a/backend/internal/handlers/projects/PromoteToPm.go b/backend/internal/handlers/projects/PromoteToPm.go new file mode 100644 index 0000000..ffe2215 --- /dev/null +++ b/backend/internal/handlers/projects/PromoteToPm.go @@ -0,0 +1,51 @@ +package projects + +import ( + db "ttime/internal/database" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" + "github.com/golang-jwt/jwt/v5" +) + +// @Summary Promote to project manager +// @Description Promote a user to project manager +// @Tags Auth +// @Security JWT +// @Accept plain +// @Produce plain +// @Param projectName path string true "Project name" +// @Param userName query string true "User name" +// @Failure 500 {string} string "Internal server error" +// @Failure 403 {string} string "Forbidden" +// @Router /promote/{projectName} [put] +// +// Login logs in a user and returns a JWT token +// Promote to project manager +func PromoteToPm(c *fiber.Ctx) error { + user := c.Locals("user").(*jwt.Token) + claims := user.Claims.(jwt.MapClaims) + pm_name := claims["name"].(string) + + project := c.Params("projectName") + new_pm_name := c.Query("userName") + + // Check if the user is a project manager + isPM, err := db.GetDb(c).IsProjectManager(pm_name, project) + if err != nil { + log.Info("Error checking if user is project manager:", err) + return c.Status(500).SendString(err.Error()) + } + + if !isPM { + log.Info("User: ", pm_name, " is not a project manager in project: ", project) + return c.Status(403).SendString("User is not a project manager") + } + + // Add the user to the project with the specified role + err = db.GetDb(c).ChangeUserRole(new_pm_name, project, "project_manager") + + // Return success message + log.Info("User : ", new_pm_name, " promoted to project manager in project: ", project) + return c.SendStatus(fiber.StatusOK) +} diff --git a/backend/main.go b/backend/main.go index 6e65386..f811a58 100644 --- a/backend/main.go +++ b/backend/main.go @@ -119,6 +119,8 @@ func main() { api.Get("/getUsersProject/:projectName", projects.ListAllUsersProject) api.Post("/project", projects.CreateProject) api.Post("/ProjectRoleChange", projects.ProjectRoleChange) + api.Put("/promoteToPm/:projectName", projects.PromoteToPm) + api.Put("/addUserToProject/:projectName", projects.AddUserToProjectHandler) api.Delete("/removeProject/:projectName", projects.RemoveProject) api.Delete("/project/:projectID", projects.DeleteProject) @@ -129,7 +131,6 @@ func main() { api.Get("/getWeeklyReportsUser/:projectName", reports.GetWeeklyReportsUserHandler) api.Post("/submitWeeklyReport", reports.SubmitWeeklyReport) api.Put("/signReport/:reportId", reports.SignReport) - api.Put("/addUserToProject", projects.AddUserToProjectHandler) api.Put("/updateWeeklyReport", reports.UpdateWeeklyReport) // Announce the port we are listening on and start the server diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index c1480fb..f8d3e5c 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -209,6 +209,19 @@ interface API { * @param {string} token The authentication token */ signReport(reportId: number, token: string): Promise>; + + /** + * Promotes a user to project manager within a project. + * + * @param {string} userName The username of the user to promote + * @param {string} projectName The name of the project to promote the user in + * @returns {Promise} A promise resolving to an API response. + */ + promoteToPm( + userName: string, + projectName: string, + token: string, + ): Promise>; } /** An instance of the API */ @@ -783,4 +796,35 @@ export const api: API = { return { success: false, message: "Failed to sign report" }; } }, + + async promoteToPm( + userName: string, + projectName: string, + token: string, + ): Promise> { + try { + const response = await fetch( + `/api/promoteToPm/${projectName}?userName=${userName}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + }, + ); + if (!response.ok) { + return { + success: false, + message: "Failed to promote user to project manager", + }; + } + } catch (e) { + return { + success: false, + message: "Failed to promote user to project manager", + }; + } + return { success: true, message: "User promoted to project manager" }; + }, }; diff --git a/testing.py b/testing.py deleted file mode 100644 index 5a181ec..0000000 --- a/testing.py +++ /dev/null @@ -1,587 +0,0 @@ -import requests -import string -import random - -debug_output = True - -def gprint(*args, **kwargs): - print("\033[92m", *args, "\033[00m", **kwargs) - -print("Running Tests...") - -def dprint(*args, **kwargs): - if debug_output: - print(*args, **kwargs) - -def randomString(len=10): - """Generate a random string of fixed length""" - letters = string.ascii_lowercase - return "".join(random.choice(letters) for i in range(len)) - - -# Defined once per test run -username = "user_" + randomString() -projectName = "project_" + randomString() - -# The base URL of the API -base_url = "http://localhost:8080" - -# Endpoint to test -registerPath = base_url + "/api/register" -loginPath = base_url + "/api/login" -addProjectPath = base_url + "/api/project" -submitReportPath = base_url + "/api/submitWeeklyReport" -getWeeklyReportPath = base_url + "/api/getWeeklyReport" -getProjectPath = base_url + "/api/project" -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" -checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager" -ProjectRoleChangePath = base_url + "/api/ProjectRoleChange" -getUsersProjectPath = base_url + "/api/getUsersProject" -getUnsignedReportsPath = base_url + "/api/getUnsignedReports" -getChangeUserNamePath = base_url + "/api/changeUserName" -getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport" -removeProjectPath = base_url + "/api/removeProject" - -#ta bort auth i handlern för att få testet att gå igenom -def test_ProjectRoleChange(): - dprint("Testing ProjectRoleChange") - localUsername = randomString() - localProjectName = randomString() - register(localUsername, "username_password") - - token = login(localUsername, "username_password").json()[ - "token" - ] - - # Just checking since this test is built somewhat differently than the others - assert token != None, "Login failed" - - response = requests.post( - addProjectPath, - json={"name": localProjectName, "description": "This is a project"}, - headers={"Authorization": "Bearer " + token}, - ) - - if response.status_code != 200: - print("Add project failed") - - response = requests.post( - ProjectRoleChangePath, - headers={"Authorization": "Bearer " + token}, - json={ - "projectName": localProjectName, - "role": "project_manager", - }, - ) - - assert response.status_code == 200, "ProjectRoleChange failed" - gprint("test_ProjectRoleChange successful") - - -def test_get_user_projects(): - username = "user2" - password = "123" - - dprint("Testing get user projects") - loginResponse = login(username, password) - # Check if the user is added to the project - response = requests.get( - getUserProjectsPath + "/" + username, - headers={"Authorization": "Bearer " + loginResponse.json()["token"]}, - ) - dprint(response.text) - dprint(response.json()) - assert response.status_code == 200, "Get user projects failed" - gprint("test_get_user_projects successful") - - -# Posts the username and password to the register endpoint -def register(username: string, password: string): - dprint("Registering with username: ", username, " and password: ", password) - response = requests.post( - registerPath, json={"username": username, "password": password} - ) - dprint(response.text) - return response - - -# Posts the username and password to the login endpoint -def login(username: string, password: string): - dprint("Logging in with username: ", username, " and password: ", password) - response = requests.post( - loginPath, json={"username": username, "password": password} - ) - dprint(response.text) - return response - - -# Test function to login -def test_login(): - response = login(username, "always_same") - assert response.status_code == 200, "Login failed" - dprint("Login successful") - gprint("test_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" - gprint("test_create_user successful") - -# Test function to add a project -def test_add_project(): - loginResponse = login(username, "always_same") - token = loginResponse.json()["token"] - response = requests.post( - addProjectPath, - json={"name": projectName, "description": "This is a project"}, - headers={"Authorization": "Bearer " + token}, - ) - dprint(response.text) - assert response.status_code == 200, "Add project failed" - gprint("test_add_project successful") - -# Test function to submit a report -def test_submit_report(): - token = login(username, "always_same").json()["token"] - response = requests.post( - submitReportPath, - json={ - "projectName": projectName, - "week": 1, - "developmentTime": 10, - "meetingTime": 5, - "adminTime": 5, - "ownWorkTime": 10, - "studyTime": 10, - "testingTime": 10, - }, - headers={"Authorization": "Bearer " + token}, - ) - dprint(response.text) - assert response.status_code == 200, "Submit report failed" - gprint("test_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}, - ) - dprint(response.text) - assert response.status_code == 200, "Get weekly report failed" - gprint("test_get_weekly_report successful") - - -# 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 - headers={"Authorization": "Bearer " + token}, - ) - dprint(response.text) - assert response.status_code == 200, "Get project failed" - gprint("test_get_project successful") - - -# 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" - dprint( - "Registering with username: ", admin_username, " and password: ", admin_password - ) - response = requests.post( - registerPath, json={"username": admin_username, "password": admin_password} - ) - dprint(response.text) - - admin_token = login(admin_username, admin_password).json()["token"] - response = requests.post( - promoteToAdminPath, - json={"username": admin_username}, - headers={"Authorization": "Bearer " + admin_token}, - ) - dprint(response.text) - assert response.status_code == 200, "Promote to site admin failed" - dprint("Admin promoted to site admin successfully") - - # Create a new user to add to the project - new_user = randomString() - register(new_user, "new_user_password") - - # Add the new user to the project as a member - response = requests.put( - addUserToProjectPath, - json={"projectName": projectName, "username": new_user, "role": "member"}, - headers={"Authorization": "Bearer " + admin_token}, - ) - - dprint(response.text) - assert response.status_code == 200, "Add user to project failed" - gprint("test_add_user_to_project successful") - -# Test function to sign a report -def test_sign_report(): - # Create a project manager user - project_manager = randomString() - register(project_manager, "project_manager_password") - - # Register an admin - admin_username = randomString() - admin_password = "admin_password2" - dprint( - "Registering with username: ", admin_username, " and password: ", admin_password - ) - response = requests.post( - registerPath, json={"username": admin_username, "password": admin_password} - ) - dprint(response.text) - - # 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.put( - addUserToProjectPath + "/" + projectName, - headers={"Authorization": "Bearer " + admin_token}, - params={"userName": project_manager} - ) - assert response.status_code == 200, "Add project manager to project failed" - dprint("Project manager added to project successfully") - - # Log in as the project manager - project_manager_token = login(project_manager, "project_manager_password").json()[ - "token" - ] - - # Submit a report for the project - token = login(username, "always_same").json()["token"] - response = requests.post( - submitReportPath, - json={ - "projectName": projectName, - "week": 2, - "developmentTime": 10, - "meetingTime": 5, - "adminTime": 5, - "ownWorkTime": 10, - "studyTime": 10, - "testingTime": 10, - }, - headers={"Authorization": "Bearer " + token}, - ) - assert response.status_code == 200, "Submit report failed" - dprint("Submit report successful") - - # Retrieve the report ID - response = requests.get( - getWeeklyReportPath, - headers={"Authorization": "Bearer " + token}, - params={"username": username, "projectName": projectName, "week": 1}, - ) - dprint(response.text) - report_id = response.json()["reportId"] - - # Sign the report as the project manager - response = requests.put( - signReportPath + "/" + str(report_id), - headers={"Authorization": "Bearer " + project_manager_token}, - ) - assert response.status_code == 200, "Sign report failed" - dprint("Sign report successful") - - # Retrieve the report ID again for confirmation - response = requests.get( - getWeeklyReportPath, - headers={"Authorization": "Bearer " + token}, - params={"username": username, "projectName": projectName, "week": 1}, - ) - 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 + "/" + projectName, - headers={"Authorization": "Bearer " + token}, - ) - - dprint(response.text) - 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 + "/" + projectName, - headers={"Authorization": "Bearer " + token}, - ) - - dprint(response.text) - assert response.status_code == 200, "Check if project manager failed" - gprint("test_check_if_project_manager successful") - -def test_ensure_manager_of_created_project(): - # Create a new user to add to the project - newUser = "karen_" + randomString() - newProject = "HR_" + randomString() - register(newUser, "new_user_password") - token = login(newUser, "new_user_password").json()["token"] - - # Create a new project - response = requests.post( - addProjectPath, - json={"name": newProject, "description": "This is a project"}, - headers={"Authorization": "Bearer " + token}, - ) - assert response.status_code == 200, "Add project failed" - - response = requests.get( - checkIfProjectManagerPath + "/" + newProject, - headers={"Authorization": "Bearer " + token}, - ) - assert response.status_code == 200, "Check if project manager failed" - assert response.json()["isProjectManager"] == True, "User is not project manager" - gprint("test_ensure_admin_of_created_project successful") - -def test_change_user_name(): - # Register a new user - new_user = randomString() - register(new_user, "password") - - # Log in as the new user - token = login(new_user, "password").json()["token"] - - # Register a new admin - admin_username = randomString() - admin_password = "admin_password" - dprint( - "Registering with username: ", admin_username, " and password: ", admin_password - ) - response = requests.post( - registerPath, json={"username": admin_username, "password": admin_password} - ) - admin_token = login(admin_username, admin_password).json()["token"] - - # Promote to admin - response = requests.post( - promoteToAdminPath, - json={"username": admin_username}, - headers={"Authorization": "Bearer " + admin_token}, - ) - - # Change the user's name - response = requests.put( - getChangeUserNamePath, - json={"prevName": new_user, "newName": randomString()}, - headers={"Authorization": "Bearer " + admin_token}, - ) - - # Check if the change was successful - assert response.status_code == 200, "Change user name failed" - gprint("test_change_user_name successful") - -def test_list_all_users_project(): - # Log in as a user who is a member of the project - admin_username = randomString() - admin_password = "admin_password2" - dprint( - "Registering with username: ", admin_username, " and password: ", admin_password - ) - response = requests.post( - registerPath, json={"username": admin_username, "password": admin_password} - ) - dprint(response.text) - - # 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}, - ) - - # Make a request to list all users associated with the project - response = requests.get( - getUsersProjectPath + "/" + projectName, - headers={"Authorization": "Bearer " + admin_token}, - ) - assert response.status_code == 200, "List all users project failed" - gprint("test_list_all_users_project sucessful") - -def test_update_weekly_report(): - # Log in as the user - token = login(username, "always_same").json()["token"] - - # Prepare the JSON data for updating the weekly report - update_data = { - "projectName": projectName, - "userName": username, - "week": 1, - "developmentTime": 8, - "meetingTime": 6, - "adminTime": 4, - "ownWorkTime": 11, - "studyTime": 8, - "testingTime": 18, - } - - # Send a request to update the weekly report - response = requests.put( - getUpdateWeeklyReportPath, - json=update_data, - headers={"Authorization": "Bearer " + token}, - ) - - # Check if the update was successful - assert response.status_code == 200, "Update weekly report failed" - gprint("test_update_weekly_report successful") - - -def test_remove_project(): - admin_username = randomString() - admin_password = "admin_password2" - dprint( - "Registering with username: ", admin_username, " and password: ", admin_password - ) - response = requests.post( - registerPath, json={"username": admin_username, "password": admin_password} - ) - dprint(response.text) - - # 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}, - ) - - # Create a new project - new_project = randomString() - response = requests.post( - addProjectPath, - json={"name": new_project, "description": "This is a project"}, - headers={"Authorization": "Bearer " + admin_token}, - ) - assert response.status_code == 200, "Add project failed" - - # Remove the project - response = requests.delete( - removeProjectPath + "/" + new_project, - headers={"Authorization": "Bearer " + admin_token}, - ) - assert response.status_code == 200, "Remove project failed" - gprint("test_remove_project successful") - -def test_get_unsigned_reports(): - # Log in as the user - token = login("user2", "123").json()["token"] - - # Make a request to get all unsigned reports - response = requests.get( - getUnsignedReportsPath + "/" + projectName, - headers={"Authorization": "Bearer " + token}, - ) - assert response.status_code == 200, "Get unsigned reports failed" - gprint("test_get_unsigned_reports successful") - -def test_get_other_users_report_as_pm(): - # Create user - user = randomString() - register(user, "password") - - # Create project - project = randomString() - pm_token = login(user, "password").json()["token"] - response = requests.post( - addProjectPath, - json={"name": project, "description": "This is a project"}, - headers={"Authorization": "Bearer " + pm_token}, - ) - assert response.status_code == 200, "Add project failed" - - # Create other user - other_user = randomString() - register(other_user, "password") - user_token = login(other_user, "password").json()["token"] - - # Add other user to project - response = requests.put( - addUserToProjectPath + "/" + project, - headers={"Authorization": "Bearer " + pm_token}, # note pm_token - params={"userName": other_user}, - ) - assert response.status_code == 200, "Add user to project failed" - - # Submit report as other user - response = requests.post( - submitReportPath, - json={ - "projectName": project, - "week": 1, - "developmentTime": 10, - "meetingTime": 5, - "adminTime": 5, - "ownWorkTime": 10, - "studyTime": 10, - "testingTime": 10, - }, - headers={"Authorization": "Bearer " + user_token}, - ) - assert response.status_code == 200, "Submit report failed" - - # Get report as project manager - response = requests.get( - getWeeklyReportPath, - headers={"Authorization": "Bearer " + pm_token}, - params={"targetUser": other_user, "projectName": project, "week": 1}, - ) - assert response.status_code == 200, "Get weekly report failed" - -if __name__ == "__main__": - test_remove_project() - test_get_user_projects() - test_create_user() - test_login() - test_add_project() - test_submit_report() - test_get_weekly_report() - test_get_project() - test_sign_report() - test_add_user_to_project() - test_get_weekly_reports_user() - test_check_if_project_manager() - test_ProjectRoleChange() - test_ensure_manager_of_created_project() - test_get_unsigned_reports() - test_list_all_users_project() - test_change_user_name() - test_update_weekly_report() - test_get_other_users_report_as_pm() - \ No newline at end of file