Merge branch 'dev'
This commit is contained in:
commit
e1b410c850
16 changed files with 329 additions and 135 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -15,6 +15,9 @@ backend/*.png
|
||||||
backend/*.jpg
|
backend/*.jpg
|
||||||
backend/*.svg
|
backend/*.svg
|
||||||
|
|
||||||
|
/go.work.sum
|
||||||
|
/package-lock.json
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
|
3
Justfile
3
Justfile
|
@ -23,10 +23,13 @@ load-release file:
|
||||||
|
|
||||||
# Tests every part of the project
|
# Tests every part of the project
|
||||||
testall:
|
testall:
|
||||||
|
cd frontend && npm install
|
||||||
cd frontend && npm test
|
cd frontend && npm test
|
||||||
cd frontend && npm run lint
|
cd frontend && npm run lint
|
||||||
|
cd frontend && npm run build
|
||||||
cd backend && make test
|
cd backend && make test
|
||||||
cd backend && make lint
|
cd backend && make lint
|
||||||
|
cd backend && make itest
|
||||||
|
|
||||||
# Cleans up everything related to the project
|
# Cleans up everything related to the project
|
||||||
clean: remove-podman-containers
|
clean: remove-podman-containers
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -13,10 +13,13 @@ remove-podman-containers:
|
||||||
|
|
||||||
# Tests every part of the project
|
# Tests every part of the project
|
||||||
testall:
|
testall:
|
||||||
|
cd frontend && npm install
|
||||||
cd frontend && npm test
|
cd frontend && npm test
|
||||||
cd frontend && npm run lint
|
cd frontend && npm run lint
|
||||||
|
cd frontend && npm run build
|
||||||
cd backend && make test
|
cd backend && make test
|
||||||
cd backend && make lint
|
cd backend && make lint
|
||||||
|
cd backend && make itest
|
||||||
|
|
||||||
# Cleans up everything related to the project
|
# Cleans up everything related to the project
|
||||||
clean: remove-podman-containers
|
clean: remove-podman-containers
|
||||||
|
|
|
@ -8,17 +8,19 @@ GOGET = $(GOCMD) get
|
||||||
# SQLite database filename
|
# SQLite database filename
|
||||||
DB_FILE = db.sqlite3
|
DB_FILE = db.sqlite3
|
||||||
|
|
||||||
|
PROC_NAME = ttime_server
|
||||||
|
|
||||||
# Directory containing migration SQL scripts
|
# Directory containing migration SQL scripts
|
||||||
MIGRATIONS_DIR = internal/database/migrations
|
MIGRATIONS_DIR = internal/database/migrations
|
||||||
SAMPLE_DATA_DIR = internal/database/sample_data
|
SAMPLE_DATA_DIR = internal/database/sample_data
|
||||||
|
|
||||||
# Build target
|
# Build target
|
||||||
build:
|
build:
|
||||||
$(GOBUILD) -o bin/server main.go
|
$(GOBUILD) -o bin/$(PROC_NAME) main.go
|
||||||
|
|
||||||
# Run target
|
# Run target
|
||||||
run: build
|
run: build
|
||||||
./bin/server
|
./bin/$(PROC_NAME)
|
||||||
|
|
||||||
watch: build
|
watch: build
|
||||||
watchexec -c -w . -r make run
|
watchexec -c -w . -r make run
|
||||||
|
@ -37,6 +39,16 @@ clean:
|
||||||
test: db.sqlite3
|
test: db.sqlite3
|
||||||
$(GOTEST) ./... -count=1
|
$(GOTEST) ./... -count=1
|
||||||
|
|
||||||
|
# Integration test target
|
||||||
|
.PHONY: itest
|
||||||
|
itest:
|
||||||
|
pgrep $(PROC_NAME) && echo "Server already running" && exit 1 || true
|
||||||
|
make build
|
||||||
|
./bin/$(PROC_NAME) >/dev/null 2>&1 &
|
||||||
|
sleep 1 # Adjust if needed
|
||||||
|
python ../testing.py
|
||||||
|
pkill $(PROC_NAME)
|
||||||
|
|
||||||
# Get dependencies target
|
# Get dependencies target
|
||||||
deps:
|
deps:
|
||||||
$(GOGET) -v ./...
|
$(GOGET) -v ./...
|
||||||
|
|
|
@ -40,8 +40,7 @@ type Database interface {
|
||||||
IsSiteAdmin(username string) (bool, error)
|
IsSiteAdmin(username string) (bool, error)
|
||||||
IsProjectManager(username string, projectname string) (bool, error)
|
IsProjectManager(username string, projectname string) (bool, error)
|
||||||
GetProjectTimes(projectName string) (map[string]int, 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
|
// 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
|
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.
|
// MigrateSampleData applies sample data to the database.
|
||||||
func (d *Db) MigrateSampleData() error {
|
func (d *Db) MigrateSampleData() error {
|
||||||
// Insert sample data
|
// Insert sample data
|
||||||
|
@ -495,34 +514,34 @@ func (d *Db) MigrateSampleData() error {
|
||||||
|
|
||||||
// GetProjectTimes retrieves a map with times per "Activity" for a given project
|
// GetProjectTimes retrieves a map with times per "Activity" for a given project
|
||||||
func (d *Db) GetProjectTimes(projectName string) (map[string]int, error) {
|
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
|
SELECT development_time, meeting_time, admin_time, own_work_time, study_time, testing_time
|
||||||
FROM weekly_reports
|
FROM weekly_reports
|
||||||
JOIN projects ON weekly_reports.project_id = projects.id
|
JOIN projects ON weekly_reports.project_id = projects.id
|
||||||
WHERE projects.name = ?
|
WHERE projects.name = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
rows, err := d.DB.Query(query, projectName)
|
rows, err := d.DB.Query(query, projectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
totalTime := make(map[string]int)
|
totalTime := make(map[string]int)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var developmentTime, meetingTime, adminTime, ownWorkTime, studyTime, testingTime int
|
var developmentTime, meetingTime, adminTime, ownWorkTime, studyTime, testingTime int
|
||||||
if err := rows.Scan(&developmentTime, &meetingTime, &adminTime, &ownWorkTime, &studyTime, &testingTime); err != nil {
|
if err := rows.Scan(&developmentTime, &meetingTime, &adminTime, &ownWorkTime, &studyTime, &testingTime); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
totalTime["development"] += developmentTime
|
totalTime["development"] += developmentTime
|
||||||
totalTime["meeting"] += meetingTime
|
totalTime["meeting"] += meetingTime
|
||||||
totalTime["admin"] += adminTime
|
totalTime["admin"] += adminTime
|
||||||
totalTime["own_work"] += ownWorkTime
|
totalTime["own_work"] += ownWorkTime
|
||||||
totalTime["study"] += studyTime
|
totalTime["study"] += studyTime
|
||||||
totalTime["testing"] += testingTime
|
totalTime["testing"] += testingTime
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -729,90 +729,89 @@ func TestIsProjectManager(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestGetProjectTimes(t *testing.T) {
|
func TestGetProjectTimes(t *testing.T) {
|
||||||
// Initialize
|
// Initialize
|
||||||
db, err := setupState()
|
db, err := setupState()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("setupState failed:", err)
|
t.Error("setupState failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a user
|
// Create a user
|
||||||
user := "TeaUser"
|
user := "TeaUser"
|
||||||
password := "Vanilla"
|
password := "Vanilla"
|
||||||
err = db.AddUser(user, password)
|
err = db.AddUser(user, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("AddUser failed:", err)
|
t.Error("AddUser failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a project
|
// Create a project
|
||||||
projectName := "ProjectVanilla"
|
projectName := "ProjectVanilla"
|
||||||
projectDescription := "When tea tastes its best"
|
projectDescription := "When tea tastes its best"
|
||||||
err = db.AddProject(projectName, projectDescription, user) // Fix the variable name here
|
err = db.AddProject(projectName, projectDescription, user) // Fix the variable name here
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("AddProject failed:", err)
|
t.Error("AddProject failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests the func in db.go
|
// Tests the func in db.go
|
||||||
totalTime, err := db.GetProjectTimes(projectName)
|
totalTime, err := db.GetProjectTimes(projectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("GetTotalTimePerActivity failed:", err)
|
t.Error("GetTotalTimePerActivity failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the totalTime map is not nil
|
// Check if the totalTime map is not nil
|
||||||
if totalTime == nil {
|
if totalTime == nil {
|
||||||
t.Error("Expected non-nil totalTime map, got nil")
|
t.Error("Expected non-nil totalTime map, got nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the expected valeus
|
// Define the expected valeus
|
||||||
expectedTotalTime := map[string]int{
|
expectedTotalTime := map[string]int{
|
||||||
"development": 0,
|
"development": 0,
|
||||||
"meeting": 0,
|
"meeting": 0,
|
||||||
"admin": 0,
|
"admin": 0,
|
||||||
"own_work": 0,
|
"own_work": 0,
|
||||||
"study": 0,
|
"study": 0,
|
||||||
"testing": 0,
|
"testing": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare the expectedTotalTime with the totalTime retrieved from the database
|
// Compare the expectedTotalTime with the totalTime retrieved from the database
|
||||||
for activity, expectedTime := range expectedTotalTime {
|
for activity, expectedTime := range expectedTotalTime {
|
||||||
if totalTime[activity] != expectedTime {
|
if totalTime[activity] != expectedTime {
|
||||||
t.Errorf("Expected %s time to be %d, got %d", activity, expectedTime, totalTime[activity])
|
t.Errorf("Expected %s time to be %d, got %d", activity, expectedTime, totalTime[activity])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert some data into the database for different activities
|
// Insert some data into the database for different activities
|
||||||
err = db.AddWeeklyReport(projectName, user, 1, 1, 3, 2, 1, 4, 5)
|
err = db.AddWeeklyReport(projectName, user, 1, 1, 3, 2, 1, 4, 5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Failed to insert data into the database:", err)
|
t.Error("Failed to insert data into the database:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newTotalTime, err := db.GetProjectTimes(projectName)
|
newTotalTime, err := db.GetProjectTimes(projectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("GetTotalTimePerActivity failed:", err)
|
t.Error("GetTotalTimePerActivity failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newExpectedTotalTime := map[string]int{
|
newExpectedTotalTime := map[string]int{
|
||||||
"development": 1,
|
"development": 1,
|
||||||
"meeting": 3,
|
"meeting": 3,
|
||||||
"admin": 2,
|
"admin": 2,
|
||||||
"own_work": 1,
|
"own_work": 1,
|
||||||
"study": 4,
|
"study": 4,
|
||||||
"testing": 5,
|
"testing": 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
for activity, newExpectedTime := range newExpectedTotalTime {
|
for activity, newExpectedTime := range newExpectedTotalTime {
|
||||||
if newTotalTime[activity] != newExpectedTime {
|
if newTotalTime[activity] != newExpectedTime {
|
||||||
t.Errorf("Expected %s time to be %d, got %d", activity, newExpectedTime, newTotalTime[activity])
|
t.Errorf("Expected %s time to be %d, got %d", activity, newExpectedTime, newTotalTime[activity])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestEnsureManagerOfCreatedProject(t *testing.T) {
|
func TestEnsureManagerOfCreatedProject(t *testing.T) {
|
||||||
db, err := setupState()
|
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.")
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ type GlobalState interface {
|
||||||
ProjectRoleChange(c *fiber.Ctx) error // To change a users role in a project
|
ProjectRoleChange(c *fiber.Ctx) error // To change a users role in a project
|
||||||
ChangeUserName(c *fiber.Ctx) error // WIP
|
ChangeUserName(c *fiber.Ctx) error // WIP
|
||||||
GetAllUsersProject(c *fiber.Ctx) error // WIP
|
GetAllUsersProject(c *fiber.Ctx) error // WIP
|
||||||
|
UpdateWeeklyReport(c *fiber.Ctx) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Constructor"
|
// "Constructor"
|
||||||
|
|
|
@ -233,3 +233,57 @@ func (gs *GState) IsProjectManagerHandler(c *fiber.Ctx) error {
|
||||||
// Return the result as JSON
|
// Return the result as JSON
|
||||||
return c.JSON(fiber.Map{"isProjectManager": isManager})
|
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)
|
||||||
|
}
|
|
@ -141,3 +141,37 @@ func (gs *GState) GetWeeklyReportsUserHandler(c *fiber.Ctx) error {
|
||||||
// Return the list of reports as JSON
|
// Return the list of reports as JSON
|
||||||
return c.JSON(reports)
|
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")
|
||||||
|
}
|
||||||
|
|
|
@ -65,3 +65,24 @@ type WeeklyReport struct {
|
||||||
// The project manager who signed it
|
// The project manager who signed it
|
||||||
SignedBy *int `json:"signedBy" db:"signed_by"`
|
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"`
|
||||||
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ func main() {
|
||||||
server.Get("/api/checkIfProjectManager/:projectName", gs.IsProjectManagerHandler)
|
server.Get("/api/checkIfProjectManager/:projectName", gs.IsProjectManagerHandler)
|
||||||
server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange)
|
server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange)
|
||||||
server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject)
|
server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject)
|
||||||
|
server.Put("/api/updateWeeklyReport", gs.UpdateWeeklyReport)
|
||||||
|
|
||||||
// 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))
|
||||||
|
|
|
@ -85,7 +85,7 @@ interface API {
|
||||||
submitWeeklyReport(
|
submitWeeklyReport(
|
||||||
weeklyReport: NewWeeklyReport,
|
weeklyReport: NewWeeklyReport,
|
||||||
token: string,
|
token: string,
|
||||||
): Promise<APIResponse<NewWeeklyReport>>;
|
): Promise<APIResponse<string>>;
|
||||||
|
|
||||||
/** Gets a weekly report for a specific user, project and week
|
/** Gets a weekly report for a specific user, project and week
|
||||||
* @param {string} projectName The name of the project.
|
* @param {string} projectName The name of the project.
|
||||||
|
@ -294,7 +294,7 @@ export const api: API = {
|
||||||
async submitWeeklyReport(
|
async submitWeeklyReport(
|
||||||
weeklyReport: NewWeeklyReport,
|
weeklyReport: NewWeeklyReport,
|
||||||
token: string,
|
token: string,
|
||||||
): Promise<APIResponse<NewWeeklyReport>> {
|
): Promise<APIResponse<string>> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/submitWeeklyReport", {
|
const response = await fetch("/api/submitWeeklyReport", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
@ -312,8 +312,8 @@ export const api: API = {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as NewWeeklyReport;
|
const data = await response.text();
|
||||||
return { success: true, data };
|
return { success: true, message: data };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
|
|
|
@ -4,23 +4,23 @@ body{
|
||||||
|
|
||||||
@keyframes backgroundTransition {
|
@keyframes backgroundTransition {
|
||||||
0% {
|
0% {
|
||||||
background-image: url('src/assets/1.jpg');
|
background-image: url('../assets/1.jpg');
|
||||||
animation-timing-function: ease-out;
|
animation-timing-function: ease-out;
|
||||||
}
|
}
|
||||||
25% {
|
25% {
|
||||||
background-image: url('src/assets/2.jpg');
|
background-image: url('../assets/2.jpg');
|
||||||
animation-timing-function: ease-in;
|
animation-timing-function: ease-in;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
background-image: url('src/assets/3.jpg');
|
background-image: url('../assets/3.jpg');
|
||||||
animation-timing-function: ease-out;
|
animation-timing-function: ease-out;
|
||||||
}
|
}
|
||||||
75% {
|
75% {
|
||||||
background-image: url('src/assets/4.jpg');
|
background-image: url('../assets/4.jpg');
|
||||||
animation-timing-function: ease-in;
|
animation-timing-function: ease-in;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
background-image: url('src/assets/1.jpg');
|
background-image: url('../assets/1.jpg');
|
||||||
animation-timing-function: ease-out;
|
animation-timing-function: ease-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
28
go.work.sum
28
go.work.sum
|
@ -1,28 +0,0 @@
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
|
||||||
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
|
||||||
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
|
||||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
|
||||||
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
|
|
||||||
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
|
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"name": "TTime",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
30
testing.py
30
testing.py
|
@ -42,6 +42,7 @@ checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager"
|
||||||
ProjectRoleChangePath = base_url + "/api/ProjectRoleChange"
|
ProjectRoleChangePath = base_url + "/api/ProjectRoleChange"
|
||||||
getUsersProjectPath = base_url + "/api/getUsersProject"
|
getUsersProjectPath = base_url + "/api/getUsersProject"
|
||||||
getChangeUserNamePath = base_url + "/api/changeUserName"
|
getChangeUserNamePath = base_url + "/api/changeUserName"
|
||||||
|
getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport"
|
||||||
|
|
||||||
#ta bort auth i handlern för att få testet att gå igenom
|
#ta bort auth i handlern för att få testet att gå igenom
|
||||||
def test_ProjectRoleChange():
|
def test_ProjectRoleChange():
|
||||||
|
@ -433,6 +434,34 @@ def test_list_all_users_project():
|
||||||
assert response.status_code == 200, "List all users project failed"
|
assert response.status_code == 200, "List all users project failed"
|
||||||
gprint("test_list_all_users_project sucessful")
|
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__":
|
if __name__ == "__main__":
|
||||||
test_get_user_projects()
|
test_get_user_projects()
|
||||||
test_create_user()
|
test_create_user()
|
||||||
|
@ -449,3 +478,4 @@ if __name__ == "__main__":
|
||||||
test_ensure_manager_of_created_project()
|
test_ensure_manager_of_created_project()
|
||||||
test_list_all_users_project()
|
test_list_all_users_project()
|
||||||
test_change_user_name()
|
test_change_user_name()
|
||||||
|
test_update_weekly_report()
|
Loading…
Reference in a new issue