unsignReport handler + API function

This commit is contained in:
al8763be 2024-04-09 17:39:10 +02:00
parent f57c445ead
commit a5e3d4259d
7 changed files with 264 additions and 0 deletions

View file

@ -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 := `

View file

@ -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()

View 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")
}

View file

@ -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))

View file

@ -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,

View file

@ -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},
)

View file

@ -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()