Compare commits

...

3 commits

Author SHA1 Message Date
Imbus
dbbe4da401 Fix for submitWeeklyReport ts API 2024-03-21 18:05:41 +01:00
Melker
ec362cfa3a GetProjectTimesHandler 2024-03-21 10:51:47 +01:00
dDogge
2d4ff7e087 Fully implemented UpdateWeeklyReport for database, handler and corresponding tests 2024-03-21 02:48:55 +01:00
9 changed files with 301 additions and 94 deletions

View file

@ -40,8 +40,7 @@ type Database interface {
IsSiteAdmin(username string) (bool, error)
IsProjectManager(username string, projectname string) (bool, error)
GetProjectTimes(projectName string) (map[string]int, error)
UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error
}
// This struct is a wrapper type that holds the database connection
@ -454,6 +453,26 @@ func (d *Db) IsProjectManager(username string, projectname string) (bool, error)
return manager, err
}
func (d *Db) UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error {
query := `
UPDATE weekly_reports
SET
development_time = ?,
meeting_time = ?,
admin_time = ?,
own_work_time = ?,
study_time = ?,
testing_time = ?
WHERE
user_id = (SELECT id FROM users WHERE username = ?)
AND project_id = (SELECT id FROM projects WHERE name = ?)
AND week = ?
`
_, err := d.Exec(query, developmentTime, meetingTime, adminTime, ownWorkTime, studyTime, testingTime, userName, projectName, week)
return err
}
// MigrateSampleData applies sample data to the database.
func (d *Db) MigrateSampleData() error {
// Insert sample data
@ -495,34 +514,34 @@ func (d *Db) MigrateSampleData() error {
// GetProjectTimes retrieves a map with times per "Activity" for a given project
func (d *Db) GetProjectTimes(projectName string) (map[string]int, error) {
query := `
query := `
SELECT development_time, meeting_time, admin_time, own_work_time, study_time, testing_time
FROM weekly_reports
JOIN projects ON weekly_reports.project_id = projects.id
WHERE projects.name = ?
`
rows, err := d.DB.Query(query, projectName)
if err != nil {
return nil, err
}
defer rows.Close()
rows, err := d.DB.Query(query, projectName)
if err != nil {
return nil, err
}
defer rows.Close()
totalTime := make(map[string]int)
for rows.Next() {
var developmentTime, meetingTime, adminTime, ownWorkTime, studyTime, testingTime int
if err := rows.Scan(&developmentTime, &meetingTime, &adminTime, &ownWorkTime, &studyTime, &testingTime); err != nil {
return nil, err
}
for rows.Next() {
var developmentTime, meetingTime, adminTime, ownWorkTime, studyTime, testingTime int
if err := rows.Scan(&developmentTime, &meetingTime, &adminTime, &ownWorkTime, &studyTime, &testingTime); err != nil {
return nil, err
}
totalTime["development"] += developmentTime
totalTime["meeting"] += meetingTime
totalTime["admin"] += adminTime
totalTime["own_work"] += ownWorkTime
totalTime["study"] += studyTime
totalTime["testing"] += testingTime
}
totalTime["development"] += developmentTime
totalTime["meeting"] += meetingTime
totalTime["admin"] += adminTime
totalTime["own_work"] += ownWorkTime
totalTime["study"] += studyTime
totalTime["testing"] += testingTime
}
if err := rows.Err(); err != nil {
return nil, err

View file

@ -729,90 +729,89 @@ func TestIsProjectManager(t *testing.T) {
}
}
func TestGetProjectTimes(t *testing.T) {
// Initialize
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
return
}
// Initialize
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
return
}
// Create a user
user := "TeaUser"
password := "Vanilla"
err = db.AddUser(user, password)
if err != nil {
t.Error("AddUser failed:", err)
return
}
// Create a user
user := "TeaUser"
password := "Vanilla"
err = db.AddUser(user, password)
if err != nil {
t.Error("AddUser failed:", err)
return
}
// Create a project
projectName := "ProjectVanilla"
projectDescription := "When tea tastes its best"
err = db.AddProject(projectName, projectDescription, user) // Fix the variable name here
if err != nil {
t.Error("AddProject failed:", err)
return
}
// Create a project
projectName := "ProjectVanilla"
projectDescription := "When tea tastes its best"
err = db.AddProject(projectName, projectDescription, user) // Fix the variable name here
if err != nil {
t.Error("AddProject failed:", err)
return
}
// Tests the func in db.go
totalTime, err := db.GetProjectTimes(projectName)
if err != nil {
t.Error("GetTotalTimePerActivity failed:", err)
return
}
// Tests the func in db.go
totalTime, err := db.GetProjectTimes(projectName)
if err != nil {
t.Error("GetTotalTimePerActivity failed:", err)
return
}
// Check if the totalTime map is not nil
if totalTime == nil {
t.Error("Expected non-nil totalTime map, got nil")
return
}
// Check if the totalTime map is not nil
if totalTime == nil {
t.Error("Expected non-nil totalTime map, got nil")
return
}
// Define the expected valeus
expectedTotalTime := map[string]int{
"development": 0,
"meeting": 0,
"admin": 0,
"own_work": 0,
"study": 0,
"testing": 0,
}
// Define the expected valeus
expectedTotalTime := map[string]int{
"development": 0,
"meeting": 0,
"admin": 0,
"own_work": 0,
"study": 0,
"testing": 0,
}
// Compare the expectedTotalTime with the totalTime retrieved from the database
for activity, expectedTime := range expectedTotalTime {
if totalTime[activity] != expectedTime {
t.Errorf("Expected %s time to be %d, got %d", activity, expectedTime, totalTime[activity])
}
}
// Compare the expectedTotalTime with the totalTime retrieved from the database
for activity, expectedTime := range expectedTotalTime {
if totalTime[activity] != expectedTime {
t.Errorf("Expected %s time to be %d, got %d", activity, expectedTime, totalTime[activity])
}
}
// Insert some data into the database for different activities
err = db.AddWeeklyReport(projectName, user, 1, 1, 3, 2, 1, 4, 5)
if err != nil {
t.Error("Failed to insert data into the database:", err)
return
}
// Insert some data into the database for different activities
err = db.AddWeeklyReport(projectName, user, 1, 1, 3, 2, 1, 4, 5)
if err != nil {
t.Error("Failed to insert data into the database:", err)
return
}
newTotalTime, err := db.GetProjectTimes(projectName)
if err != nil {
t.Error("GetTotalTimePerActivity failed:", err)
return
}
if err != nil {
t.Error("GetTotalTimePerActivity failed:", err)
return
}
newExpectedTotalTime := map[string]int{
"development": 1,
"meeting": 3,
"admin": 2,
"own_work": 1,
"study": 4,
"testing": 5,
}
"development": 1,
"meeting": 3,
"admin": 2,
"own_work": 1,
"study": 4,
"testing": 5,
}
for activity, newExpectedTime := range newExpectedTotalTime {
if newTotalTime[activity] != newExpectedTime {
t.Errorf("Expected %s time to be %d, got %d", activity, newExpectedTime, newTotalTime[activity])
}
}
if newTotalTime[activity] != newExpectedTime {
t.Errorf("Expected %s time to be %d, got %d", activity, newExpectedTime, newTotalTime[activity])
}
}
}
func TestEnsureManagerOfCreatedProject(t *testing.T) {
db, err := setupState()
@ -847,3 +846,51 @@ func TestEnsureManagerOfCreatedProject(t *testing.T) {
t.Error("Expected testuser to be a project manager, but it's not.")
}
}
// TestUpdateWeeklyReport tests the UpdateWeeklyReport function of the database
func TestUpdateWeeklyReport(t *testing.T) {
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
}
// Add a user
err = db.AddUser("testuser", "password")
if err != nil {
t.Error("AddUser failed:", err)
}
// Add a project
err = db.AddProject("testproject", "description", "testuser")
if err != nil {
t.Error("AddProject failed:", err)
}
// Add a weekly report
err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1)
if err != nil {
t.Error("AddWeeklyReport failed:", err)
}
// Update the weekly report
err = db.UpdateWeeklyReport("testproject", "testuser", 1, 2, 2, 2, 2, 2, 2)
if err != nil {
t.Error("UpdateWeeklyReport failed:", err)
}
// Retrieve the updated report
updatedReport, err := db.GetWeeklyReport("testuser", "testproject", 1)
if err != nil {
t.Error("GetWeeklyReport failed:", err)
}
// Check if the report was updated correctly
if updatedReport.DevelopmentTime != 2 ||
updatedReport.MeetingTime != 2 ||
updatedReport.AdminTime != 2 ||
updatedReport.OwnWorkTime != 2 ||
updatedReport.StudyTime != 2 ||
updatedReport.TestingTime != 2 {
t.Error("UpdateWeeklyReport failed: report not updated correctly")
}
}

View file

@ -28,6 +28,7 @@ type GlobalState interface {
ProjectRoleChange(c *fiber.Ctx) error // To change a users role in a project
ChangeUserName(c *fiber.Ctx) error // WIP
GetAllUsersProject(c *fiber.Ctx) error // WIP
UpdateWeeklyReport(c *fiber.Ctx) error
}
// "Constructor"

View file

@ -233,3 +233,57 @@ func (gs *GState) IsProjectManagerHandler(c *fiber.Ctx) error {
// Return the result as JSON
return c.JSON(fiber.Map{"isProjectManager": isManager})
}
func (gs *GState) GetProjectTimesHandler(c *fiber.Ctx) error {
// Get the username from the token
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
username := claims["name"].(string)
// Get project
projectName := c.Params("projectName")
if projectName == "" {
log.Info("No project name provided")
return c.Status(400).SendString("No project name provided")
}
// Get all users in the project and roles
userProjects, err := gs.Db.GetAllUsersProject(projectName)
if err != nil {
log.Info("Error getting users in project:", err)
return c.Status(500).SendString(err.Error())
}
// If the user is member
isMember := false
for _, userProject := range userProjects {
if userProject.Username == username {
isMember = true
break
}
}
// If the user is admin
if !isMember {
isAdmin, err := gs.Db.IsSiteAdmin(username)
if err != nil {
log.Info("Error checking admin status:", err)
return c.Status(500).SendString(err.Error())
}
if !isAdmin {
log.Info("User is neither a project member nor a site admin:", username)
return c.Status(403).SendString("User is neither a project member nor a site admin")
}
}
// Get project times
projectTimes, err := gs.Db.GetProjectTimes(projectName)
if err != nil {
log.Info("Error getting project times:", err)
return c.Status(500).SendString(err.Error())
}
// Return project times as JSON
log.Info("Returning project times for project:", projectName)
return c.JSON(projectTimes)
}

View file

@ -141,3 +141,37 @@ func (gs *GState) GetWeeklyReportsUserHandler(c *fiber.Ctx) error {
// Return the list of reports as JSON
return c.JSON(reports)
}
func (gs *GState) UpdateWeeklyReport(c *fiber.Ctx) error {
// Extract the necessary parameters from the token
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
username := claims["name"].(string)
// Parse the request body into an UpdateWeeklyReport struct
var updateReport types.UpdateWeeklyReport
if err := c.BodyParser(&updateReport); 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 updateReport.Week < 1 || updateReport.Week > 52 {
log.Info("Invalid week number")
return c.Status(400).SendString("Invalid week number")
}
if updateReport.DevelopmentTime < 0 || updateReport.MeetingTime < 0 || updateReport.AdminTime < 0 || updateReport.OwnWorkTime < 0 || updateReport.StudyTime < 0 || updateReport.TestingTime < 0 {
log.Info("Invalid time report")
return c.Status(400).SendString("Invalid time report")
}
// Update the weekly report in the database
if err := gs.Db.UpdateWeeklyReport(updateReport.ProjectName, username, updateReport.Week, updateReport.DevelopmentTime, updateReport.MeetingTime, updateReport.AdminTime, updateReport.OwnWorkTime, updateReport.StudyTime, updateReport.TestingTime); err != nil {
log.Info("Error updating weekly report in db:", err)
return c.Status(500).SendString(err.Error())
}
log.Info("Weekly report updated")
return c.Status(200).SendString("Weekly report updated")
}

View file

@ -65,3 +65,24 @@ type WeeklyReport struct {
// The project manager who signed it
SignedBy *int `json:"signedBy" db:"signed_by"`
}
type UpdateWeeklyReport struct {
// The name of the project, as it appears in the database
ProjectName string `json:"projectName"`
// The name of the user
UserName string `json:"userName"`
// The week number
Week int `json:"week"`
// Total time spent on development
DevelopmentTime int `json:"developmentTime"`
// Total time spent in meetings
MeetingTime int `json:"meetingTime"`
// Total time spent on administrative tasks
AdminTime int `json:"adminTime"`
// Total time spent on personal projects
OwnWorkTime int `json:"ownWorkTime"`
// Total time spent on studying
StudyTime int `json:"studyTime"`
// Total time spent on testing
TestingTime int `json:"testingTime"`
}

View file

@ -101,6 +101,7 @@ func main() {
server.Get("/api/checkIfProjectManager/:projectName", gs.IsProjectManagerHandler)
server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange)
server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject)
server.Put("/api/updateWeeklyReport", gs.UpdateWeeklyReport)
// Announce the port we are listening on and start the server
err = server.Listen(fmt.Sprintf(":%d", conf.Port))

View file

@ -85,7 +85,7 @@ interface API {
submitWeeklyReport(
weeklyReport: NewWeeklyReport,
token: string,
): Promise<APIResponse<NewWeeklyReport>>;
): Promise<APIResponse<string>>;
/** Gets a weekly report for a specific user, project and week
* @param {string} projectName The name of the project.
@ -294,7 +294,7 @@ export const api: API = {
async submitWeeklyReport(
weeklyReport: NewWeeklyReport,
token: string,
): Promise<APIResponse<NewWeeklyReport>> {
): Promise<APIResponse<string>> {
try {
const response = await fetch("/api/submitWeeklyReport", {
method: "POST",
@ -312,8 +312,8 @@ export const api: API = {
};
}
const data = (await response.json()) as NewWeeklyReport;
return { success: true, data };
const data = await response.text();
return { success: true, message: data };
} catch (e) {
return {
success: false,

View file

@ -42,6 +42,7 @@ checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager"
ProjectRoleChangePath = base_url + "/api/ProjectRoleChange"
getUsersProjectPath = base_url + "/api/getUsersProject"
getChangeUserNamePath = base_url + "/api/changeUserName"
getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport"
#ta bort auth i handlern för att få testet att gå igenom
def test_ProjectRoleChange():
@ -433,6 +434,34 @@ def test_list_all_users_project():
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")
if __name__ == "__main__":
test_get_user_projects()
test_create_user()
@ -449,3 +478,4 @@ if __name__ == "__main__":
test_ensure_manager_of_created_project()
test_list_all_users_project()
test_change_user_name()
test_update_weekly_report()