From 21cc7ff8a393769cfbc81dc07fe822f64482cb07 Mon Sep 17 00:00:00 2001
From: dDogge <>
Date: Sun, 17 Mar 2024 15:34:48 +0100
Subject: [PATCH 01/10] Added signed_by attribute to weekly_report SQL table

---
 backend/internal/database/migrations/0035_weekly_report.sql | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/backend/internal/database/migrations/0035_weekly_report.sql b/backend/internal/database/migrations/0035_weekly_report.sql
index 0e29b97..47610b5 100644
--- a/backend/internal/database/migrations/0035_weekly_report.sql
+++ b/backend/internal/database/migrations/0035_weekly_report.sql
@@ -8,7 +8,9 @@ CREATE TABLE weekly_reports (
   own_work_time INTEGER,
   study_time INTEGER,
   testing_time INTEGER,
+  signed_by INTEGER,
   FOREIGN KEY (user_id) REFERENCES users(id),
-  FOREIGN KEY (project_id) REFERENCES projects(id)
+  FOREIGN KEY (project_id) REFERENCES projects(id),
+  FOREIGN KEY (signed_by) REFERENCES users(id),
   PRIMARY KEY (user_id, project_id, week)
 )
\ No newline at end of file

From 670ed46d5188d72eb6f67695e342d4542e9a9c72 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sun, 17 Mar 2024 16:41:29 +0100
Subject: [PATCH 02/10] WeeklyReport type as represented in the db

---
 backend/internal/types/WeeklyReport.go | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/backend/internal/types/WeeklyReport.go b/backend/internal/types/WeeklyReport.go
index e0ea1ef..43c19c6 100644
--- a/backend/internal/types/WeeklyReport.go
+++ b/backend/internal/types/WeeklyReport.go
@@ -19,3 +19,26 @@ type NewWeeklyReport struct {
 	// Total time spent on testing
 	TestingTime int `json:"testingTime"`
 }
+
+type WeeklyReport struct {
+	// The ID of the report
+	ReportId int `json:"reportId" db:"report_id"`
+	// The user id of the user who submitted the report
+	UserId int `json:"userId" db:"user_id"`
+	// The name of the project, as it appears in the database
+	ProjectName string `json:"projectName"`
+	// 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"`
+}

From d6fc0594a9e24c08b6f2c750c64ba4dcd60be294 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sun, 17 Mar 2024 16:55:40 +0100
Subject: [PATCH 03/10] Splitting backend endpoints into smaller bits

---
 backend/internal/handlers/global_state.go     | 226 ------------------
 .../handlers/handlers_project_related.go      |  98 ++++++++
 .../handlers/handlers_report_related.go       |  34 +++
 .../handlers/handlers_user_related.go         | 116 +++++++++
 4 files changed, 248 insertions(+), 226 deletions(-)
 create mode 100644 backend/internal/handlers/handlers_project_related.go
 create mode 100644 backend/internal/handlers/handlers_report_related.go
 create mode 100644 backend/internal/handlers/handlers_user_related.go

diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go
index 2378f7b..01c8999 100644
--- a/backend/internal/handlers/global_state.go
+++ b/backend/internal/handlers/global_state.go
@@ -1,13 +1,9 @@
 package handlers
 
 import (
-	"strconv"
-	"time"
 	"ttime/internal/database"
-	"ttime/internal/types"
 
 	"github.com/gofiber/fiber/v2"
-	"github.com/golang-jwt/jwt/v5"
 )
 
 // The actual interface that we will use
@@ -51,50 +47,6 @@ type GState struct {
 	ButtonCount int
 }
 
-// Register is a simple handler that registers a new user
-//
-//	@Summary		Register a new user
-//	@Description	Register a new user
-//	@Tags			User
-//	@Accept			json
-//	@Produce		json
-//	@Success		200	{string}	string	"User added"
-//	@Failure		400	{string}	string	"Bad request"
-//	@Failure		500	{string}	string	"Internal server error"
-//	@Router			/api/register [post]
-func (gs *GState) Register(c *fiber.Ctx) error {
-	u := new(types.NewUser)
-	if err := c.BodyParser(u); err != nil {
-		return c.Status(400).SendString(err.Error())
-	}
-
-	if err := gs.Db.AddUser(u.Username, u.Password); err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	return c.Status(200).SendString("User added")
-}
-
-// This path should obviously be protected in the future
-// UserDelete deletes a user from the database
-func (gs *GState) UserDelete(c *fiber.Ctx) error {
-	// Read from path parameters
-	username := c.Params("username")
-
-	// Read username from Locals
-	auth_username := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)["name"].(string)
-
-	if username != auth_username {
-		return c.Status(403).SendString("You can only delete yourself")
-	}
-
-	if err := gs.Db.RemoveUser(username); err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	return c.Status(200).SendString("User deleted")
-}
-
 func (gs *GState) GetButtonCount(c *fiber.Ctx) error {
 	return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount})
 }
@@ -103,181 +55,3 @@ func (gs *GState) IncrementButtonCount(c *fiber.Ctx) error {
 	gs.ButtonCount++
 	return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount})
 }
-
-// Login is a simple login handler that returns a JWT token
-func (gs *GState) Login(c *fiber.Ctx) error {
-	// The body type is identical to a NewUser
-	u := new(types.NewUser)
-	if err := c.BodyParser(u); err != nil {
-		return c.Status(400).SendString(err.Error())
-	}
-
-	if !gs.Db.CheckUser(u.Username, u.Password) {
-		println("User not found")
-		return c.SendStatus(fiber.StatusUnauthorized)
-	}
-
-	// Create the Claims
-	claims := jwt.MapClaims{
-		"name":  u.Username,
-		"admin": false,
-		"exp":   time.Now().Add(time.Hour * 72).Unix(),
-	}
-
-	// Create token
-	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
-
-	// Generate encoded token and send it as response.
-	t, err := token.SignedString([]byte("secret"))
-	if err != nil {
-		return c.SendStatus(fiber.StatusInternalServerError)
-	}
-
-	return c.JSON(fiber.Map{"token": t})
-}
-
-// LoginRenew is a simple handler that renews the token
-func (gs *GState) LoginRenew(c *fiber.Ctx) error {
-	// For testing: curl localhost:3000/restricted -H "Authorization: Bearer <token>"
-	user := c.Locals("user").(*jwt.Token)
-	claims := user.Claims.(jwt.MapClaims)
-	claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
-	renewed := jwt.MapClaims{
-		"name":  claims["name"],
-		"admin": claims["admin"],
-		"exp":   claims["exp"],
-	}
-	token := jwt.NewWithClaims(jwt.SigningMethodHS256, renewed)
-	t, err := token.SignedString([]byte("secret"))
-	if err != nil {
-		return c.SendStatus(fiber.StatusInternalServerError)
-	}
-	return c.JSON(fiber.Map{"token": t})
-}
-
-// CreateProject is a simple handler that creates a new project
-func (gs *GState) CreateProject(c *fiber.Ctx) error {
-	user := c.Locals("user").(*jwt.Token)
-
-	p := new(types.NewProject)
-	if err := c.BodyParser(p); err != nil {
-		return c.Status(400).SendString(err.Error())
-	}
-
-	// Get the username from the token and set it as the owner of the project
-	// This is ugly but
-	claims := user.Claims.(jwt.MapClaims)
-	owner := claims["name"].(string)
-
-	if err := gs.Db.AddProject(p.Name, p.Description, owner); err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	return c.Status(200).SendString("Project added")
-}
-
-// GetUserProjects returns all projects that the user is a member of
-func (gs *GState) GetUserProjects(c *fiber.Ctx) error {
-	// First we get the username from the token
-	user := c.Locals("user").(*jwt.Token)
-	claims := user.Claims.(jwt.MapClaims)
-	username := claims["name"].(string)
-
-	// Then dip into the database to get the projects
-	projects, err := gs.Db.GetProjectsForUser(username)
-	if err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	// Return a json serialized list of projects
-	return c.JSON(projects)
-}
-
-// ListAllUsers is a handler that returns a list of all users in the application database
-func (gs *GState) ListAllUsers(c *fiber.Ctx) error {
-	// Get all users from the database
-	users, err := gs.Db.GetAllUsersApplication()
-	if err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	// Return the list of users as JSON
-	return c.JSON(users)
-}
-
-func (gs *GState) ListAllUsersProject(c *fiber.Ctx) error {
-	// Extract the project name from the request parameters or body
-	projectName := c.Params("projectName")
-
-	// Get all users associated with the project from the database
-	users, err := gs.Db.GetAllUsersProject(projectName)
-	if err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	// Return the list of users as JSON
-	return c.JSON(users)
-}
-
-// ProjectRoleChange is a handler that changes a user's role within a project
-func (gs *GState) ProjectRoleChange(c *fiber.Ctx) error {
-	// Extract the necessary parameters from the request
-	username := c.Params("username")
-	projectName := c.Params("projectName")
-	role := c.Params("role")
-
-	// Change the user's role within the project in the database
-	if err := gs.Db.ChangeUserRole(username, projectName, role); err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	// Return a success message
-	return c.SendStatus(fiber.StatusOK)
-}
-
-// GetProject retrieves a specific project by its ID
-func (gs *GState) GetProject(c *fiber.Ctx) error {
-	// Extract the project ID from the request parameters or body
-	projectID := c.Params("projectID")
-
-	// Parse the project ID into an integer
-	projectIDInt, err := strconv.Atoi(projectID)
-	if err != nil {
-		return c.Status(400).SendString("Invalid project ID")
-	}
-
-	// Get the project from the database by its ID
-	project, err := gs.Db.GetProject(projectIDInt)
-	if err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	// Return the project as JSON
-	return c.JSON(project)
-}
-
-func (gs *GState) SubmitWeeklyReport(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)
-
-	report := new(types.NewWeeklyReport)
-	if err := c.BodyParser(report); err != nil {
-		return c.Status(400).SendString(err.Error())
-	}
-
-	// Make sure all the fields of the report are valid
-	if report.Week < 1 || report.Week > 52 {
-		return c.Status(400).SendString("Invalid week number")
-	}
-	if report.DevelopmentTime < 0 || report.MeetingTime < 0 || report.AdminTime < 0 || report.OwnWorkTime < 0 || report.StudyTime < 0 || report.TestingTime < 0 {
-		return c.Status(400).SendString("Invalid time report")
-	}
-
-	if err := gs.Db.AddWeeklyReport(report.ProjectName, username, report.Week, report.DevelopmentTime, report.MeetingTime, report.AdminTime, report.OwnWorkTime, report.StudyTime, report.TestingTime); err != nil {
-		return c.Status(500).SendString(err.Error())
-	}
-
-	return c.Status(200).SendString("Time report added")
-}
diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go
new file mode 100644
index 0000000..6a430e9
--- /dev/null
+++ b/backend/internal/handlers/handlers_project_related.go
@@ -0,0 +1,98 @@
+package handlers
+
+import (
+	"strconv"
+	"ttime/internal/types"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/golang-jwt/jwt/v5"
+)
+
+// CreateProject is a simple handler that creates a new project
+func (gs *GState) CreateProject(c *fiber.Ctx) error {
+	user := c.Locals("user").(*jwt.Token)
+
+	p := new(types.NewProject)
+	if err := c.BodyParser(p); err != nil {
+		return c.Status(400).SendString(err.Error())
+	}
+
+	// Get the username from the token and set it as the owner of the project
+	// This is ugly but
+	claims := user.Claims.(jwt.MapClaims)
+	owner := claims["name"].(string)
+
+	if err := gs.Db.AddProject(p.Name, p.Description, owner); err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	return c.Status(200).SendString("Project added")
+}
+
+// GetUserProjects returns all projects that the user is a member of
+func (gs *GState) GetUserProjects(c *fiber.Ctx) error {
+	// First we get the username from the token
+	user := c.Locals("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	username := claims["name"].(string)
+
+	// Then dip into the database to get the projects
+	projects, err := gs.Db.GetProjectsForUser(username)
+	if err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	// Return a json serialized list of projects
+	return c.JSON(projects)
+}
+
+// ProjectRoleChange is a handler that changes a user's role within a project
+func (gs *GState) ProjectRoleChange(c *fiber.Ctx) error {
+	// Extract the necessary parameters from the request
+	username := c.Params("username")
+	projectName := c.Params("projectName")
+	role := c.Params("role")
+
+	// Change the user's role within the project in the database
+	if err := gs.Db.ChangeUserRole(username, projectName, role); err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	// Return a success message
+	return c.SendStatus(fiber.StatusOK)
+}
+
+// GetProject retrieves a specific project by its ID
+func (gs *GState) GetProject(c *fiber.Ctx) error {
+	// Extract the project ID from the request parameters or body
+	projectID := c.Params("projectID")
+
+	// Parse the project ID into an integer
+	projectIDInt, err := strconv.Atoi(projectID)
+	if err != nil {
+		return c.Status(400).SendString("Invalid project ID")
+	}
+
+	// Get the project from the database by its ID
+	project, err := gs.Db.GetProject(projectIDInt)
+	if err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	// Return the project as JSON
+	return c.JSON(project)
+}
+
+func (gs *GState) ListAllUsersProject(c *fiber.Ctx) error {
+	// Extract the project name from the request parameters or body
+	projectName := c.Params("projectName")
+
+	// Get all users associated with the project from the database
+	users, err := gs.Db.GetAllUsersProject(projectName)
+	if err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	// Return the list of users as JSON
+	return c.JSON(users)
+}
diff --git a/backend/internal/handlers/handlers_report_related.go b/backend/internal/handlers/handlers_report_related.go
new file mode 100644
index 0000000..2486091
--- /dev/null
+++ b/backend/internal/handlers/handlers_report_related.go
@@ -0,0 +1,34 @@
+package handlers
+
+import (
+	"ttime/internal/types"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/golang-jwt/jwt/v5"
+)
+
+func (gs *GState) SubmitWeeklyReport(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)
+
+	report := new(types.NewWeeklyReport)
+	if err := c.BodyParser(report); err != nil {
+		return c.Status(400).SendString(err.Error())
+	}
+
+	// Make sure all the fields of the report are valid
+	if report.Week < 1 || report.Week > 52 {
+		return c.Status(400).SendString("Invalid week number")
+	}
+	if report.DevelopmentTime < 0 || report.MeetingTime < 0 || report.AdminTime < 0 || report.OwnWorkTime < 0 || report.StudyTime < 0 || report.TestingTime < 0 {
+		return c.Status(400).SendString("Invalid time report")
+	}
+
+	if err := gs.Db.AddWeeklyReport(report.ProjectName, username, report.Week, report.DevelopmentTime, report.MeetingTime, report.AdminTime, report.OwnWorkTime, report.StudyTime, report.TestingTime); err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	return c.Status(200).SendString("Time report added")
+}
diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go
new file mode 100644
index 0000000..e90abd0
--- /dev/null
+++ b/backend/internal/handlers/handlers_user_related.go
@@ -0,0 +1,116 @@
+package handlers
+
+import (
+	"time"
+	"ttime/internal/types"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/golang-jwt/jwt/v5"
+)
+
+// Register is a simple handler that registers a new user
+//
+//	@Summary		Register a new user
+//	@Description	Register a new user
+//	@Tags			User
+//	@Accept			json
+//	@Produce		json
+//	@Success		200	{string}	string	"User added"
+//	@Failure		400	{string}	string	"Bad request"
+//	@Failure		500	{string}	string	"Internal server error"
+//	@Router			/api/register [post]
+func (gs *GState) Register(c *fiber.Ctx) error {
+	u := new(types.NewUser)
+	if err := c.BodyParser(u); err != nil {
+		return c.Status(400).SendString(err.Error())
+	}
+
+	if err := gs.Db.AddUser(u.Username, u.Password); err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	return c.Status(200).SendString("User added")
+}
+
+// This path should obviously be protected in the future
+// UserDelete deletes a user from the database
+func (gs *GState) UserDelete(c *fiber.Ctx) error {
+	// Read from path parameters
+	username := c.Params("username")
+
+	// Read username from Locals
+	auth_username := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)["name"].(string)
+
+	if username != auth_username {
+		return c.Status(403).SendString("You can only delete yourself")
+	}
+
+	if err := gs.Db.RemoveUser(username); err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	return c.Status(200).SendString("User deleted")
+}
+
+// Login is a simple login handler that returns a JWT token
+func (gs *GState) Login(c *fiber.Ctx) error {
+	// The body type is identical to a NewUser
+	u := new(types.NewUser)
+	if err := c.BodyParser(u); err != nil {
+		return c.Status(400).SendString(err.Error())
+	}
+
+	if !gs.Db.CheckUser(u.Username, u.Password) {
+		println("User not found")
+		return c.SendStatus(fiber.StatusUnauthorized)
+	}
+
+	// Create the Claims
+	claims := jwt.MapClaims{
+		"name":  u.Username,
+		"admin": false,
+		"exp":   time.Now().Add(time.Hour * 72).Unix(),
+	}
+
+	// Create token
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+
+	// Generate encoded token and send it as response.
+	t, err := token.SignedString([]byte("secret"))
+	if err != nil {
+		return c.SendStatus(fiber.StatusInternalServerError)
+	}
+
+	return c.JSON(fiber.Map{"token": t})
+}
+
+// LoginRenew is a simple handler that renews the token
+func (gs *GState) LoginRenew(c *fiber.Ctx) error {
+	// For testing: curl localhost:3000/restricted -H "Authorization: Bearer <token>"
+	user := c.Locals("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
+	renewed := jwt.MapClaims{
+		"name":  claims["name"],
+		"admin": claims["admin"],
+		"exp":   claims["exp"],
+	}
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, renewed)
+	t, err := token.SignedString([]byte("secret"))
+	if err != nil {
+		return c.SendStatus(fiber.StatusInternalServerError)
+	}
+	return c.JSON(fiber.Map{"token": t})
+}
+
+// ListAllUsers is a handler that returns a list of all users in the application database
+func (gs *GState) ListAllUsers(c *fiber.Ctx) error {
+	// Get all users from the database
+	users, err := gs.Db.GetAllUsersApplication()
+	if err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	// Return the list of users as JSON
+	return c.JSON(users)
+}

From c90d4956363f37bcb1a9d2abebba1486dd0a823d Mon Sep 17 00:00:00 2001
From: dDogge <>
Date: Sun, 17 Mar 2024 17:47:31 +0100
Subject: [PATCH 04/10] Added new types and changed SQL since apperently sqlite
 does use autoincrement

---
 .../internal/database/migrations/0010_users.sql  |  2 +-
 .../database/migrations/0020_projects.sql        |  2 +-
 .../database/migrations/0035_weekly_report.sql   | 12 ++++++------
 backend/internal/types/WeeklyReport.go           | 16 ++++++++--------
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/backend/internal/database/migrations/0010_users.sql b/backend/internal/database/migrations/0010_users.sql
index 5c9d329..d2e2dd1 100644
--- a/backend/internal/database/migrations/0010_users.sql
+++ b/backend/internal/database/migrations/0010_users.sql
@@ -3,7 +3,7 @@
 -- username is what is used for login
 -- password is the hashed password
 CREATE TABLE IF NOT EXISTS users (
-  id INTEGER PRIMARY KEY,
+  id INTEGER PRIMARY KEY AUTOINCREMENT,
   userId TEXT DEFAULT (HEX(RANDOMBLOB(4))) NOT NULL UNIQUE,
   username VARCHAR(255) NOT NULL UNIQUE,
   password VARCHAR(255) NOT NULL
diff --git a/backend/internal/database/migrations/0020_projects.sql b/backend/internal/database/migrations/0020_projects.sql
index 58d8e97..99bce86 100644
--- a/backend/internal/database/migrations/0020_projects.sql
+++ b/backend/internal/database/migrations/0020_projects.sql
@@ -1,5 +1,5 @@
 CREATE TABLE IF NOT EXISTS projects (
-  id INTEGER PRIMARY KEY,
+  id INTEGER PRIMARY KEY AUTOINCREMENT,
   name VARCHAR(255) NOT NULL UNIQUE,
   description TEXT NOT NULL,
   owner_user_id INTEGER NOT NULL,
diff --git a/backend/internal/database/migrations/0035_weekly_report.sql b/backend/internal/database/migrations/0035_weekly_report.sql
index 47610b5..366d932 100644
--- a/backend/internal/database/migrations/0035_weekly_report.sql
+++ b/backend/internal/database/migrations/0035_weekly_report.sql
@@ -1,7 +1,8 @@
 CREATE TABLE weekly_reports (
-  user_id INTEGER,
-  project_id INTEGER,
-  week INTEGER,
+  report_id INTEGER PRIMARY KEY AUTOINCREMENT,
+  user_id INTEGER NOT NULL,
+  project_id INTEGER NOT NULL,
+  week INTEGER NOT NULL,
   development_time INTEGER,
   meeting_time INTEGER,
   admin_time INTEGER,
@@ -11,6 +12,5 @@ CREATE TABLE weekly_reports (
   signed_by INTEGER,
   FOREIGN KEY (user_id) REFERENCES users(id),
   FOREIGN KEY (project_id) REFERENCES projects(id),
-  FOREIGN KEY (signed_by) REFERENCES users(id),
-  PRIMARY KEY (user_id, project_id, week)
-)
\ No newline at end of file
+  FOREIGN KEY (signed_by) REFERENCES users(id)
+);
\ No newline at end of file
diff --git a/backend/internal/types/WeeklyReport.go b/backend/internal/types/WeeklyReport.go
index 43c19c6..a9a6264 100644
--- a/backend/internal/types/WeeklyReport.go
+++ b/backend/internal/types/WeeklyReport.go
@@ -26,19 +26,19 @@ type WeeklyReport struct {
 	// The user id of the user who submitted the report
 	UserId int `json:"userId" db:"user_id"`
 	// The name of the project, as it appears in the database
-	ProjectName string `json:"projectName"`
+	ProjectId string `json:"projectId" db:"project_id"`
 	// The week number
-	Week int `json:"week"`
+	Week int `json:"week" db:"week"`
 	// Total time spent on development
-	DevelopmentTime int `json:"developmentTime"`
+	DevelopmentTime int `json:"developmentTime" db:"development_time"`
 	// Total time spent in meetings
-	MeetingTime int `json:"meetingTime"`
+	MeetingTime int `json:"meetingTime" db:"meeting_time"`
 	// Total time spent on administrative tasks
-	AdminTime int `json:"adminTime"`
+	AdminTime int `json:"adminTime" db:"admin_time"`
 	// Total time spent on personal projects
-	OwnWorkTime int `json:"ownWorkTime"`
+	OwnWorkTime int `json:"ownWorkTime" db:"own_work_time"`
 	// Total time spent on studying
-	StudyTime int `json:"studyTime"`
+	StudyTime int `json:"studyTime" db:"study_time"`
 	// Total time spent on testing
-	TestingTime int `json:"testingTime"`
+	TestingTime int `json:"testingTime" db:"testing_time"`
 }

From a77e57e496a72f2dd9e77cfdc5aa7fb00d442ae9 Mon Sep 17 00:00:00 2001
From: dDogge <>
Date: Sun, 17 Mar 2024 17:58:02 +0100
Subject: [PATCH 05/10] Added GetWeeklyReport function and corresponding test

---
 backend/internal/database/db.go        | 26 +++++++++++++++++
 backend/internal/database/db_test.go   | 39 ++++++++++++++++++++++++++
 backend/internal/types/WeeklyReport.go |  2 +-
 3 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go
index 320327a..7f4a89c 100644
--- a/backend/internal/database/db.go
+++ b/backend/internal/database/db.go
@@ -29,6 +29,7 @@ type Database interface {
 	GetAllProjects() ([]types.Project, error)
 	GetProject(projectId int) (types.Project, error)
 	GetUserRole(username string, projectname string) (string, error)
+	GetWeeklyReport(username string, projectName string, week int) (types.WeeklyReport, error)
 }
 
 // This struct is a wrapper type that holds the database connection
@@ -256,6 +257,31 @@ func (d *Db) GetAllUsersApplication() ([]string, error) {
 	return usernames, nil
 }
 
+func (d *Db) GetWeeklyReport(username string, projectName string, week int) (types.WeeklyReport, error) {
+	var report types.WeeklyReport
+	query := `
+        SELECT
+            report_id,
+            user_id,
+            project_id,
+            week,
+            development_time,
+            meeting_time,
+            admin_time,
+            own_work_time,
+            study_time,
+            testing_time
+        FROM
+            weekly_reports
+        WHERE
+            user_id = (SELECT id FROM users WHERE username = ?)
+            AND project_id = (SELECT id FROM projects WHERE name = ?)
+            AND week = ?
+    `
+	err := d.Get(&report, query, username, projectName, week)
+	return report, err
+}
+
 // Reads a directory of migration files and applies them to the database.
 // This will eventually be used on an embedded directory
 func (d *Db) Migrate() error {
diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go
index 9124c45..f791066 100644
--- a/backend/internal/database/db_test.go
+++ b/backend/internal/database/db_test.go
@@ -371,3 +371,42 @@ func TestAddProject(t *testing.T) {
 		t.Error("Added project not found")
 	}
 }
+
+func TestGetWeeklyReport(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)
+	}
+
+	report, err := db.GetWeeklyReport("testuser", "testproject", 1)
+	if err != nil {
+		t.Error("GetWeeklyReport failed:", err)
+	}
+
+	// Check if the retrieved report matches the expected values
+	if report.UserId != 1 {
+		t.Errorf("Expected UserId to be 1, got %d", report.UserId)
+	}
+	if report.ProjectId != 1 {
+		t.Errorf("Expected ProjectId to be 1, got %d", report.ProjectId)
+	}
+	if report.Week != 1 {
+		t.Errorf("Expected Week to be 1, got %d", report.Week)
+	}
+	// Check other fields similarly
+}
diff --git a/backend/internal/types/WeeklyReport.go b/backend/internal/types/WeeklyReport.go
index a9a6264..b704cc8 100644
--- a/backend/internal/types/WeeklyReport.go
+++ b/backend/internal/types/WeeklyReport.go
@@ -26,7 +26,7 @@ type WeeklyReport struct {
 	// The user id of the user who submitted the report
 	UserId int `json:"userId" db:"user_id"`
 	// The name of the project, as it appears in the database
-	ProjectId string `json:"projectId" db:"project_id"`
+	ProjectId int `json:"projectId" db:"project_id"`
 	// The week number
 	Week int `json:"week" db:"week"`
 	// Total time spent on development

From 3e00a532cf54b47602dd887eb3d971b7de2ce8c6 Mon Sep 17 00:00:00 2001
From: dDogge <>
Date: Sun, 17 Mar 2024 18:05:54 +0100
Subject: [PATCH 06/10] Added handler for GetWeeklyReport

---
 backend/internal/handlers/global_state.go     |  1 +
 .../handlers/handlers_report_related.go       | 28 +++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go
index 01c8999..57a1969 100644
--- a/backend/internal/handlers/global_state.go
+++ b/backend/internal/handlers/global_state.go
@@ -15,6 +15,7 @@ type GlobalState interface {
 	CreateProject(c *fiber.Ctx) error   // To create a new project
 	GetUserProjects(c *fiber.Ctx) error // To get all projects
 	SubmitWeeklyReport(c *fiber.Ctx) error
+	GetWeeklyReport(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 2486091..8754afd 100644
--- a/backend/internal/handlers/handlers_report_related.go
+++ b/backend/internal/handlers/handlers_report_related.go
@@ -1,6 +1,7 @@
 package handlers
 
 import (
+	"strconv"
 	"ttime/internal/types"
 
 	"github.com/gofiber/fiber/v2"
@@ -32,3 +33,30 @@ func (gs *GState) SubmitWeeklyReport(c *fiber.Ctx) error {
 
 	return c.Status(200).SendString("Time report added")
 }
+
+// Handler for retrieving weekly report
+func (gs *GState) GetWeeklyReport(c *fiber.Ctx) error {
+	// Extract the necessary parameters from the request
+	user := c.Locals("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	username := claims["name"].(string)
+
+	// Extract project name and week from query parameters
+	projectName := c.Query("projectName")
+	week := c.Query("week")
+
+	// Convert week to integer
+	weekInt, err := strconv.Atoi(week)
+	if err != nil {
+		return c.Status(400).SendString("Invalid week number")
+	}
+
+	// Call the database function to get the weekly report
+	report, err := gs.Db.GetWeeklyReport(username, projectName, weekInt)
+	if err != nil {
+		return c.Status(500).SendString(err.Error())
+	}
+
+	// Return the retrieved weekly report
+	return c.JSON(report)
+}

From 14668ea675942a0bdf81acd290885a2f70a3bded Mon Sep 17 00:00:00 2001
From: al8763be <al8763be-s@student.lu.se>
Date: Sun, 17 Mar 2024 19:05:39 +0100
Subject: [PATCH 07/10] Test file for API

---
 frontend/src/API/API.test.ts | 88 ++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 frontend/src/API/API.test.ts

diff --git a/frontend/src/API/API.test.ts b/frontend/src/API/API.test.ts
new file mode 100644
index 0000000..e0a93f6
--- /dev/null
+++ b/frontend/src/API/API.test.ts
@@ -0,0 +1,88 @@
+import { describe, expect, test } from "@jest/globals";
+import { api } from "../API/API";
+import { NewUser, NewWeeklyReport } from "../Types/goTypes";
+
+describe("API", () => {
+  test("registerUser", async () => {
+    const user: NewUser = {
+      username: "lol", // Add the username property
+      password: "lol",
+    };
+
+    const response = await api.registerUser(user);
+
+    expect(response.success).toBe(true);
+    expect(response.data).toHaveProperty("userId");
+  });
+
+  test("createProject", async () => {
+    const project = {
+      name: "Project X",
+      description: "This is a test project",
+    };
+    const token =
+      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
+
+    const response = await api.createProject(project, token);
+
+    expect(response.success).toBe(true);
+    expect(response.data).toHaveProperty("projectId");
+  });
+
+  test("renewToken", async () => {
+    const refreshToken =
+      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
+
+    const response = await api.renewToken(refreshToken);
+
+    expect(response.success).toBe(true);
+    expect(response.data).toHaveProperty("accessToken");
+    expect(response.data).toHaveProperty("refreshToken");
+  });
+
+  test("getUserProjects", async () => {
+    const token =
+      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
+    const username = "rrgumdzpmc";
+    const response = await api.getUserProjects(username, token);
+
+    expect(response.success).toBe(true);
+    expect(response.data).toHaveProperty("projects");
+  });
+
+  test("submitWeeklyReport", async () => {
+    const report: NewWeeklyReport = {
+      projectName: "vtmosxssst",
+      week: 2,
+      developmentTime: 40,
+      meetingTime: 5,
+      adminTime: 2,
+      ownWorkTime: 10,
+      studyTime: 12,
+      testingTime: 41,
+    };
+    const token =
+      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
+
+    const response = await api.submitWeeklyReport(report, token);
+
+    expect(response.success).toBe(true);
+    expect(response.data).toHaveProperty(
+      "message",
+      "Report submitted successfully",
+    );
+  });
+
+  test("login", async () => {
+    const user: NewUser = {
+      username: "rrgumdzpmc", // Add an empty string value for the username property
+      password: "always_same",
+    };
+
+    const response = await api.login(user);
+
+    expect(response.success).toBe(true);
+    expect(response.data).toHaveProperty("accessToken");
+    expect(response.data).toHaveProperty("refreshToken");
+  });
+});

From 30cf0b606589c8eac370984d964783a1a2ad604f Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sun, 17 Mar 2024 19:07:49 +0100
Subject: [PATCH 08/10] Making linter bro happy

---
 frontend/src/Components/LoginCheck.tsx        | 14 ++---
 frontend/src/Components/ProjectListUser.tsx   |  2 +-
 frontend/src/Components/Register.tsx          |  4 +-
 frontend/src/Components/TimeReport.tsx        | 52 ++++++++++---------
 frontend/src/Components/UserListAdmin.tsx     |  8 +--
 .../Pages/UserPages/UserNewTimeReportPage.tsx |  2 +-
 6 files changed, 43 insertions(+), 39 deletions(-)

diff --git a/frontend/src/Components/LoginCheck.tsx b/frontend/src/Components/LoginCheck.tsx
index ccf761d..af45d0f 100644
--- a/frontend/src/Components/LoginCheck.tsx
+++ b/frontend/src/Components/LoginCheck.tsx
@@ -1,30 +1,30 @@
-import { NewUser } from "../Types/Users";
+import { NewUser } from "../Types/goTypes";
 
 function LoginCheck(props: { username: string; password: string }): number {
   //Example users for testing without backend, remove when using backend
   const admin: NewUser = {
-    userName: "admin",
+    username: "admin",
     password: "123",
   };
   const pmanager: NewUser = {
-    userName: "pmanager",
+    username: "pmanager",
     password: "123",
   };
   const user: NewUser = {
-    userName: "user",
+    username: "user",
     password: "123",
   };
 
   //TODO: Compare with db instead when finished
-  if (props.username === admin.userName && props.password === admin.password) {
+  if (props.username === admin.username && props.password === admin.password) {
     return 1;
   } else if (
-    props.username === pmanager.userName &&
+    props.username === pmanager.username &&
     props.password === pmanager.password
   ) {
     return 2;
   } else if (
-    props.username === user.userName &&
+    props.username === user.username &&
     props.password === user.password
   ) {
     return 3;
diff --git a/frontend/src/Components/ProjectListUser.tsx b/frontend/src/Components/ProjectListUser.tsx
index 0502159..96eeaff 100644
--- a/frontend/src/Components/ProjectListUser.tsx
+++ b/frontend/src/Components/ProjectListUser.tsx
@@ -1,5 +1,5 @@
 import { Link } from "react-router-dom";
-import { Project } from "../Types/Project";
+import { Project } from "../Types/goTypes";
 
 /**
  * The props for the ProjectsProps component
diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx
index 0c0fcd0..f3d773e 100644
--- a/frontend/src/Components/Register.tsx
+++ b/frontend/src/Components/Register.tsx
@@ -1,5 +1,5 @@
 import { useState } from "react";
-import { NewUser } from "../Types/Users";
+import { NewUser } from "../Types/goTypes";
 import { api } from "../API/API";
 import Logo from "../assets/Logo.svg";
 import Button from "./Button";
@@ -35,7 +35,7 @@ export default function Register(): JSX.Element {
   const [password, setPassword] = useState("");
 
   const handleRegister = async (): Promise<void> => {
-    const newUser: NewUser = { userName: username, password };
+    const newUser: NewUser = { username: username, password };
     await api.registerUser(newUser); // TODO: Handle errors
   };
 
diff --git a/frontend/src/Components/TimeReport.tsx b/frontend/src/Components/TimeReport.tsx
index cb33ad9..e7eb5b7 100644
--- a/frontend/src/Components/TimeReport.tsx
+++ b/frontend/src/Components/TimeReport.tsx
@@ -1,40 +1,44 @@
 import { useState } from "react";
-import { TimeReport } from "../Types/TimeReport";
 import { api } from "../API/API";
 import { useNavigate } from "react-router-dom";
 import Button from "./Button";
+import { NewWeeklyReport } from "../Types/goTypes";
 
 export default function NewTimeReport(): JSX.Element {
-  const [week, setWeek] = useState("");
-  const [development, setDevelopment] = useState("0");
-  const [meeting, setMeeting] = useState("0");
-  const [administration, setAdministration] = useState("0");
-  const [ownwork, setOwnWork] = useState("0");
-  const [studies, setStudies] = useState("0");
-  const [testing, setTesting] = useState("0");
+  const [projectName, setProjectName] = useState<string>("projectName"); // TODO: Get from backend
+  const [week, setWeek] = useState<number>(NaN);
+  const [development, setDevelopment] = useState<number>(NaN);
+  const [meeting, setMeeting] = useState<number>(NaN);
+  const [administration, setAdministration] = useState<number>(NaN);
+  const [ownwork, setOwnWork] = useState<number>(NaN);
+  const [studies, setStudies] = useState<number>(NaN);
+  const [testing, setTesting] = useState<number>(NaN);
 
   const handleNewTimeReport = async (): Promise<void> => {
-    const newTimeReport: TimeReport = {
+    const newTimeReport: NewWeeklyReport = {
+      projectName,
       week,
-      development,
-      meeting,
-      administration,
-      ownwork,
-      studies,
-      testing,
+      developmentTime: development,
+      meetingTime: meeting,
+      adminTime: administration,
+      ownWorkTime: ownwork,
+      studyTime: studies,
+      testingTime: testing,
     };
     await Promise.resolve();
-    // await api.registerTimeReport(newTimeReport); This needs to be implemented!
+    await api.submitWeeklyReport(newTimeReport, "token");
   };
 
   const navigate = useNavigate();
 
+  setProjectName("Something Reasonable"); // This should obviously not be used here
+
   return (
     <>
       <div className="border-4 border-black bg-white flex flex-col justify-start min-h-[65vh] h-fit w-[50vw] rounded-3xl overflow-scroll space-y-[2vh] p-[30px] items-center">
         <form
           onSubmit={(e) => {
-            if (week === "") {
+            if (!week) {
               alert("Please enter a week number");
               e.preventDefault();
               return;
@@ -50,7 +54,7 @@ export default function NewTimeReport(): JSX.Element {
               type="week"
               placeholder="Week"
               onChange={(e) => {
-                const weekNumber = e.target.value.split("-W")[1];
+                const weekNumber = parseInt(e.target.value.split("-W")[1]);
                 setWeek(weekNumber);
               }}
               onKeyDown={(event) => {
@@ -81,7 +85,7 @@ export default function NewTimeReport(): JSX.Element {
                       className="border-2 border-black rounded-md text-center w-1/2"
                       value={development}
                       onChange={(e) => {
-                        setDevelopment(e.target.value);
+                        setDevelopment(parseInt(e.target.value));
                       }}
                       onKeyDown={(event) => {
                         const keyValue = event.key;
@@ -100,7 +104,7 @@ export default function NewTimeReport(): JSX.Element {
                       className="border-2 border-black rounded-md text-center w-1/2"
                       value={meeting}
                       onChange={(e) => {
-                        setMeeting(e.target.value);
+                        setMeeting(parseInt(e.target.value));
                       }}
                       onKeyDown={(event) => {
                         const keyValue = event.key;
@@ -119,7 +123,7 @@ export default function NewTimeReport(): JSX.Element {
                       className="border-2 border-black rounded-md text-center w-1/2"
                       value={administration}
                       onChange={(e) => {
-                        setAdministration(e.target.value);
+                        setAdministration(parseInt(e.target.value));
                       }}
                       onKeyDown={(event) => {
                         const keyValue = event.key;
@@ -138,7 +142,7 @@ export default function NewTimeReport(): JSX.Element {
                       className="border-2 border-black rounded-md text-center w-1/2"
                       value={ownwork}
                       onChange={(e) => {
-                        setOwnWork(e.target.value);
+                        setOwnWork(parseInt(e.target.value));
                       }}
                       onKeyDown={(event) => {
                         const keyValue = event.key;
@@ -157,7 +161,7 @@ export default function NewTimeReport(): JSX.Element {
                       className="border-2 border-black rounded-md text-center w-1/2"
                       value={studies}
                       onChange={(e) => {
-                        setStudies(e.target.value);
+                        setStudies(parseInt(e.target.value));
                       }}
                       onKeyDown={(event) => {
                         const keyValue = event.key;
@@ -176,7 +180,7 @@ export default function NewTimeReport(): JSX.Element {
                       className="border-2 border-black rounded-md text-center w-1/2"
                       value={testing}
                       onChange={(e) => {
-                        setTesting(e.target.value);
+                        setTesting(parseInt(e.target.value));
                       }}
                       onKeyDown={(event) => {
                         const keyValue = event.key;
diff --git a/frontend/src/Components/UserListAdmin.tsx b/frontend/src/Components/UserListAdmin.tsx
index 42fb094..e25ad5f 100644
--- a/frontend/src/Components/UserListAdmin.tsx
+++ b/frontend/src/Components/UserListAdmin.tsx
@@ -1,5 +1,5 @@
 import { Link } from "react-router-dom";
-import { User } from "../Types/Users";
+import { User } from "../Types/goTypes";
 
 /**
  * The props for the UserProps component
@@ -23,9 +23,9 @@ export function UserListAdmin(props: UserProps): JSX.Element {
     <div>
       <ul className="font-bold underline text-[30px] cursor-pointer padding">
         {props.users.map((user) => (
-          <Link to="/admin-view-user" key={user.id} state={user.userName}>
-            <li className="pt-5" key={user.id}>
-              {user.userName}
+          <Link to="/admin-view-user" key={user.userId} state={user.username}>
+            <li className="pt-5" key={user.userId}>
+              {user.username}
             </li>
           </Link>
         ))}
diff --git a/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx b/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx
index 85c80df..ca84770 100644
--- a/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx
+++ b/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx
@@ -1,7 +1,7 @@
 import BasicWindow from "../../Components/BasicWindow";
 import Button from "../../Components/Button";
 import NewTimeReport from "../../Components/TimeReport";
-import BackButton from "../../Components/BackButton";
+import { Link } from "react-router-dom";
 
 function UserNewTimeReportPage(): JSX.Element {
   const content = (

From 9240d5e0521203031339766fda169662b2761520 Mon Sep 17 00:00:00 2001
From: Imbus <>
Date: Sun, 17 Mar 2024 19:24:13 +0100
Subject: [PATCH 09/10] Verbose debug printing in login endpoint

---
 backend/internal/handlers/handlers_user_related.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go
index e90abd0..c1c8abe 100644
--- a/backend/internal/handlers/handlers_user_related.go
+++ b/backend/internal/handlers/handlers_user_related.go
@@ -57,9 +57,11 @@ func (gs *GState) Login(c *fiber.Ctx) error {
 	// The body type is identical to a NewUser
 	u := new(types.NewUser)
 	if err := c.BodyParser(u); err != nil {
+		println("Error parsing body")
 		return c.Status(400).SendString(err.Error())
 	}
 
+	println("Username:", u.Username)
 	if !gs.Db.CheckUser(u.Username, u.Password) {
 		println("User not found")
 		return c.SendStatus(fiber.StatusUnauthorized)
@@ -74,13 +76,16 @@ func (gs *GState) Login(c *fiber.Ctx) error {
 
 	// Create token
 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+	println("Token created for user:", u.Username)
 
 	// Generate encoded token and send it as response.
 	t, err := token.SignedString([]byte("secret"))
 	if err != nil {
+		println("Error signing token")
 		return c.SendStatus(fiber.StatusInternalServerError)
 	}
 
+	println("Successfully signed token for user:", u.Username)
 	return c.JSON(fiber.Map{"token": t})
 }
 

From 402b0ac08b189faad3b94a41abdd29b85d6e5749 Mon Sep 17 00:00:00 2001
From: al8763be <al8763be-s@student.lu.se>
Date: Sun, 17 Mar 2024 19:28:03 +0100
Subject: [PATCH 10/10] Update API.test.ts

---
 frontend/src/API/API.test.ts | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/frontend/src/API/API.test.ts b/frontend/src/API/API.test.ts
index e0a93f6..dbae706 100644
--- a/frontend/src/API/API.test.ts
+++ b/frontend/src/API/API.test.ts
@@ -8,9 +8,8 @@ describe("API", () => {
       username: "lol", // Add the username property
       password: "lol",
     };
-
     const response = await api.registerUser(user);
-
+    console.log(response.message);
     expect(response.success).toBe(true);
     expect(response.data).toHaveProperty("userId");
   });
@@ -24,7 +23,7 @@ describe("API", () => {
       "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
 
     const response = await api.createProject(project, token);
-
+    console.log(response.message);
     expect(response.success).toBe(true);
     expect(response.data).toHaveProperty("projectId");
   });
@@ -34,7 +33,7 @@ describe("API", () => {
       "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
 
     const response = await api.renewToken(refreshToken);
-
+    console.log(response.message);
     expect(response.success).toBe(true);
     expect(response.data).toHaveProperty("accessToken");
     expect(response.data).toHaveProperty("refreshToken");
@@ -45,7 +44,7 @@ describe("API", () => {
       "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
     const username = "rrgumdzpmc";
     const response = await api.getUserProjects(username, token);
-
+    console.log(response.message);
     expect(response.success).toBe(true);
     expect(response.data).toHaveProperty("projects");
   });
@@ -65,7 +64,7 @@ describe("API", () => {
       "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImV4cCI6MTcxMDk0MDIwMywibmFtZSI6InJyZ3VtZHpwbWMifQ.V9NHoYMYV61t";
 
     const response = await api.submitWeeklyReport(report, token);
-
+    console.log(response.message);
     expect(response.success).toBe(true);
     expect(response.data).toHaveProperty(
       "message",
@@ -80,7 +79,7 @@ describe("API", () => {
     };
 
     const response = await api.login(user);
-
+    console.log(response.message);
     expect(response.success).toBe(true);
     expect(response.data).toHaveProperty("accessToken");
     expect(response.data).toHaveProperty("refreshToken");