unsignReport handler + API function
This commit is contained in:
		
							parent
							
								
									f57c445ead
								
							
						
					
					
						commit
						a5e3d4259d
					
				
					 7 changed files with 264 additions and 0 deletions
				
			
		|  | @ -45,6 +45,7 @@ type Database interface { | ||||||
| 	UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error | 	UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error | ||||||
| 	RemoveProject(projectname string) error | 	RemoveProject(projectname string) error | ||||||
| 	GetUserName(id int) (string, error) | 	GetUserName(id int) (string, error) | ||||||
|  | 	UnsignWeeklyReport(reportId int, projectManagerId int) error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // This struct is a wrapper type that holds the database connection | // This struct is a wrapper type that holds the database connection | ||||||
|  | @ -372,6 +373,36 @@ func (d *Db) SignWeeklyReport(reportId int, projectManagerId int) error { | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (d *Db) UnsignWeeklyReport(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 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	managerQuery := `SELECT project_id FROM user_roles  | ||||||
|  | 					WHERE user_id = ? | ||||||
|  | 					AND project_id = (SELECT project_id FROM weekly_reports WHERE report_id = ?)  | ||||||
|  | 					AND p_role = 'project_manager'` | ||||||
|  | 
 | ||||||
|  | 	// Retrieve the project ID associated with the project manager | ||||||
|  | 	var managerProjectID int | ||||||
|  | 	err = d.Get(&managerProjectID, managerQuery, projectManagerId, reportId) | ||||||
|  | 	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 unsign the report") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Update the signed_by field of the specified report | ||||||
|  | 	_, err = d.Exec("UPDATE weekly_reports SET signed_by = NULL WHERE report_id = ?;", projectManagerId, reportId) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (d *Db) GetUnsignedWeeklyReports(projectName string) ([]types.WeeklyReport, error) { | func (d *Db) GetUnsignedWeeklyReports(projectName string) ([]types.WeeklyReport, error) { | ||||||
| 	// Define the SQL query to fetch unsigned reports for a given user | 	// Define the SQL query to fetch unsigned reports for a given user | ||||||
| 	query := ` | 	query := ` | ||||||
|  |  | ||||||
|  | @ -583,6 +583,94 @@ func TestSignWeeklyReport(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestUnsignWeeklyReport(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) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 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) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Unsign the report | ||||||
|  | 	err = db.UnsignWeeklyReport(report.ReportId, projectManagerID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error("UnsignWeeklyReport failed:", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Retrieve the report again to check if it's unsigned | ||||||
|  | 	unsignedReport, err := db.GetWeeklyReport("testuser", "testproject", 1) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error("GetWeeklyReport failed:", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Ensure the report is unsigned | ||||||
|  | 	if unsignedReport.SignedBy != nil { | ||||||
|  | 		t.Error("Expected SignedBy to be nil, got", unsignedReport.SignedBy) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // TestSignWeeklyReportByAnotherProjectManager tests the scenario where a project manager attempts to sign a weekly report for a user who is not assigned to their project | // TestSignWeeklyReportByAnotherProjectManager tests the scenario where a project manager attempts to sign a weekly report for a user who is not assigned to their project | ||||||
| func TestSignWeeklyReportByAnotherProjectManager(t *testing.T) { | func TestSignWeeklyReportByAnotherProjectManager(t *testing.T) { | ||||||
| 	db, err := setupState() | 	db, err := setupState() | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								backend/internal/handlers/reports/UnsignReport.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								backend/internal/handlers/reports/UnsignReport.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | package reports | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"strconv" | ||||||
|  | 	db "ttime/internal/database" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gofiber/fiber/v2" | ||||||
|  | 	"github.com/gofiber/fiber/v2/log" | ||||||
|  | 	"github.com/golang-jwt/jwt/v5" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func UnsignReport(c *fiber.Ctx) error { | ||||||
|  | 	// Extract the necessary parameters from the token | ||||||
|  | 	user := c.Locals("user").(*jwt.Token) | ||||||
|  | 	claims := user.Claims.(jwt.MapClaims) | ||||||
|  | 	projectManagerUsername := claims["name"].(string) | ||||||
|  | 
 | ||||||
|  | 	// Extract report ID from the path | ||||||
|  | 	reportId, err := strconv.Atoi(c.Params("reportId")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Info("Invalid report ID") | ||||||
|  | 		return c.Status(400).SendString("Invalid report ID") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Get the project manager's ID | ||||||
|  | 	projectManagerID, err := db.GetDb(c).GetUserId(projectManagerUsername) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Info("Failed to get project manager ID for user: ", projectManagerUsername) | ||||||
|  | 		return c.Status(500).SendString("Failed to get project manager ID") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Call the database function to sign the weekly report | ||||||
|  | 	err = db.GetDb(c).UnsignWeeklyReport(reportId, projectManagerID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Info("Error Unsigning weekly report:", err) | ||||||
|  | 		return c.Status(500).SendString(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Info("Project manager ID: ", projectManagerID, " signed report ID: ", reportId) | ||||||
|  | 	return c.Status(200).SendString("Weekly report unsigned successfully") | ||||||
|  | } | ||||||
|  | @ -126,6 +126,7 @@ func main() { | ||||||
| 	api.Delete("/removeProject/:projectName", projects.RemoveProject) | 	api.Delete("/removeProject/:projectName", projects.RemoveProject) | ||||||
| 	api.Delete("/project/:projectID", projects.DeleteProject) | 	api.Delete("/project/:projectID", projects.DeleteProject) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	// All report related routes | 	// All report related routes | ||||||
| 	// reportGroup := api.Group("/report") // Not currently in use | 	// reportGroup := api.Group("/report") // Not currently in use | ||||||
| 	api.Get("/getWeeklyReport", reports.GetWeeklyReport) | 	api.Get("/getWeeklyReport", reports.GetWeeklyReport) | ||||||
|  | @ -134,6 +135,7 @@ func main() { | ||||||
| 	api.Post("/submitWeeklyReport", reports.SubmitWeeklyReport) | 	api.Post("/submitWeeklyReport", reports.SubmitWeeklyReport) | ||||||
| 	api.Put("/signReport/:reportId", reports.SignReport) | 	api.Put("/signReport/:reportId", reports.SignReport) | ||||||
| 	api.Put("/updateWeeklyReport", reports.UpdateWeeklyReport) | 	api.Put("/updateWeeklyReport", reports.UpdateWeeklyReport) | ||||||
|  | 	api.Put("/unsignReport/:reportId", reports.UnsignReport) | ||||||
| 
 | 
 | ||||||
| 	// Announce the port we are listening on and start the server | 	// Announce the port we are listening on and start the server | ||||||
| 	err = server.Listen(fmt.Sprintf(":%d", conf.Port)) | 	err = server.Listen(fmt.Sprintf(":%d", conf.Port)) | ||||||
|  |  | ||||||
|  | @ -221,6 +221,15 @@ interface API { | ||||||
|    */ |    */ | ||||||
|   signReport(reportId: number, token: string): Promise<APIResponse<string>>; |   signReport(reportId: number, token: string): Promise<APIResponse<string>>; | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * Unsigns a report. Keep in mind that the user which the token belongs to must be | ||||||
|  |    * the project manager of the project the report belongs to. | ||||||
|  |    * | ||||||
|  |    * @param {number} reportId The id of the report to sign | ||||||
|  |    * @param {string} token The authentication token | ||||||
|  |    */ | ||||||
|  |   unsignReport(reportId: number, token: string): Promise<APIResponse<string>>; | ||||||
|  | 
 | ||||||
|   /** |   /** | ||||||
|    * Promotes a user to project manager within a project. |    * Promotes a user to project manager within a project. | ||||||
|    * |    * | ||||||
|  | @ -846,6 +855,29 @@ export const api: API = { | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|  |   async unsignReport( | ||||||
|  |     reportId: number, | ||||||
|  |     token: string, | ||||||
|  |   ): Promise<APIResponse<string>> { | ||||||
|  |     try { | ||||||
|  |       const response = await fetch(`/api/unsignReport/${reportId}`, { | ||||||
|  |         method: "PUT", | ||||||
|  |         headers: { | ||||||
|  |           "Content-Type": "application/json", | ||||||
|  |           Authorization: "Bearer " + token, | ||||||
|  |         }, | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       if (!response.ok) { | ||||||
|  |         return { success: false, message: "Failed to unsign report" }; | ||||||
|  |       } else { | ||||||
|  |         return { success: true, message: "Report unsigned" }; | ||||||
|  |       } | ||||||
|  |     } catch (e) { | ||||||
|  |       return { success: false, message: "Failed to unsign report" }; | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
|   async promoteToPm( |   async promoteToPm( | ||||||
|     userName: string, |     userName: string, | ||||||
|     projectName: string, |     projectName: string, | ||||||
|  |  | ||||||
|  | @ -34,6 +34,7 @@ getChangeUserNamePath = base_url + "/api/changeUserName" | ||||||
| getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport" | getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport" | ||||||
| removeProjectPath = base_url + "/api/removeProject" | removeProjectPath = base_url + "/api/removeProject" | ||||||
| promoteToPmPath = base_url + "/api/promoteToPm" | promoteToPmPath = base_url + "/api/promoteToPm" | ||||||
|  | unsignReportPath = base_url + "/api/unsignReport" | ||||||
| 
 | 
 | ||||||
| debug_output = False | debug_output = False | ||||||
| 
 | 
 | ||||||
|  | @ -149,3 +150,9 @@ def signReport(project_manager_token: string, report_id: int): | ||||||
|         signReportPath + "/" + str(report_id), |         signReportPath + "/" + str(report_id), | ||||||
|         headers={"Authorization": "Bearer " + project_manager_token}, |         headers={"Authorization": "Bearer " + project_manager_token}, | ||||||
|     ) |     ) | ||||||
|  | 
 | ||||||
|  | def unsignReport(project_manager_token: string, report_id: int): | ||||||
|  |     return requests.put( | ||||||
|  |         unsignReportPath + "/" + str(report_id), | ||||||
|  |         headers={"Authorization": "Bearer " + project_manager_token}, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  | @ -215,6 +215,68 @@ def test_sign_report(): | ||||||
|     assert report_id != None, "Get report failed" |     assert report_id != None, "Get report failed" | ||||||
|     gprint("test_sign_report successful") |     gprint("test_sign_report successful") | ||||||
| 
 | 
 | ||||||
|  | # Test function to unsign a report | ||||||
|  | def test_unsign_report(): | ||||||
|  |     # Pm user | ||||||
|  |     pm_username = "pm" + randomString() | ||||||
|  |     pm_password = "admin_password2" | ||||||
|  | 
 | ||||||
|  |     # User to add | ||||||
|  |     member_user = "member" + randomString() | ||||||
|  |     member_passwd = "password" | ||||||
|  | 
 | ||||||
|  |     # Name of the project to be created | ||||||
|  |     project_name = "project" + randomString() | ||||||
|  | 
 | ||||||
|  |     # Register and get the tokens for both users | ||||||
|  |     pm_token = register_and_login(pm_username, pm_password) | ||||||
|  |     member_token = register_and_login(member_user, member_passwd) | ||||||
|  | 
 | ||||||
|  |     # Create the project | ||||||
|  |     response = create_project(pm_token, project_name) | ||||||
|  |     assert response.status_code == 200, "Create project failed" | ||||||
|  | 
 | ||||||
|  |     # Add the user to the project | ||||||
|  |     response = addToProject(pm_token, member_user, project_name) | ||||||
|  | 
 | ||||||
|  |     # Submit a report for the project | ||||||
|  |     response = submitReport( | ||||||
|  |         member_token, | ||||||
|  |         { | ||||||
|  |             "projectName": project_name, | ||||||
|  |             "week": 1, | ||||||
|  |             "developmentTime": 10, | ||||||
|  |             "meetingTime": 5, | ||||||
|  |             "adminTime": 5, | ||||||
|  |             "ownWorkTime": 10, | ||||||
|  |             "studyTime": 10, | ||||||
|  |             "testingTime": 10, | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|  |     assert response.status_code == 200, "Submit report failed" | ||||||
|  | 
 | ||||||
|  |     # Retrieve the report ID | ||||||
|  |     report_id = getReport(member_token, member_user, project_name)["reportId"] | ||||||
|  | 
 | ||||||
|  |     # Sign the report as the project manager | ||||||
|  |     response = signReport(pm_token, report_id) | ||||||
|  |     assert response.status_code == 200, "Sign report failed" | ||||||
|  |     dprint("Sign  report successful") | ||||||
|  | 
 | ||||||
|  |     # Retrieve the report ID again for confirmation | ||||||
|  |     report_id = getReport(member_token, member_user, project_name)["reportId"] | ||||||
|  |     assert report_id != None, "Get report failed" | ||||||
|  | 
 | ||||||
|  |     # Unsign the report as the project manager | ||||||
|  |     response = unsignReport(pm_token, report_id) | ||||||
|  |     assert response.status_code == 200, "Unsign report failed" | ||||||
|  |     dprint("Unsign report successful") | ||||||
|  | 
 | ||||||
|  |     # Retrieve the report ID again for confirmation | ||||||
|  |     report_id = getReport(member_token, member_user, project_name)["reportId"] | ||||||
|  |     assert report_id != None, "Get report failed" | ||||||
|  |     gprint("test_unsign_report successful") | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| # Test function to get weekly reports for a user in a project | # Test function to get weekly reports for a user in a project | ||||||
| def test_get_all_weekly_reports(): | def test_get_all_weekly_reports(): | ||||||
|  | @ -497,6 +559,7 @@ def test_promote_to_manager(): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|  |     test_unsign_report() | ||||||
|     test_promote_to_manager() |     test_promote_to_manager() | ||||||
|     test_remove_project() |     test_remove_project() | ||||||
|     test_get_user_projects() |     test_get_user_projects() | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 al8763be
						al8763be