Co-authored-by: Imbus <imbus64@users.noreply.github.com>
This commit is contained in:
		
						commit
						9a54175d49
					
				
					 36 changed files with 735 additions and 151 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -15,6 +15,9 @@ backend/*.png
 | 
			
		|||
backend/*.jpg
 | 
			
		||||
backend/*.svg
 | 
			
		||||
 | 
			
		||||
/go.work.sum
 | 
			
		||||
/package-lock.json
 | 
			
		||||
 | 
			
		||||
# Test binary, built with `go test -c`
 | 
			
		||||
*.test
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								Justfile
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								Justfile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -23,10 +23,13 @@ load-release file:
 | 
			
		|||
 | 
			
		||||
# Tests every part of the project
 | 
			
		||||
testall:
 | 
			
		||||
    cd frontend && npm install
 | 
			
		||||
    cd frontend && npm test
 | 
			
		||||
    cd frontend && npm run lint
 | 
			
		||||
    cd frontend && npm run build
 | 
			
		||||
    cd backend && make test
 | 
			
		||||
    cd backend && make lint
 | 
			
		||||
    cd backend && make itest
 | 
			
		||||
 | 
			
		||||
# Cleans up everything related to the project
 | 
			
		||||
clean: remove-podman-containers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -13,10 +13,13 @@ remove-podman-containers:
 | 
			
		|||
 | 
			
		||||
# Tests every part of the project
 | 
			
		||||
testall:
 | 
			
		||||
	cd frontend && npm install
 | 
			
		||||
	cd frontend && npm test
 | 
			
		||||
	cd frontend && npm run lint
 | 
			
		||||
	cd frontend && npm run build
 | 
			
		||||
	cd backend && make test
 | 
			
		||||
	cd backend && make lint
 | 
			
		||||
	cd backend && make itest
 | 
			
		||||
 | 
			
		||||
# Cleans up everything related to the project
 | 
			
		||||
clean: remove-podman-containers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,17 +8,19 @@ GOGET = $(GOCMD) get
 | 
			
		|||
# SQLite database filename
 | 
			
		||||
DB_FILE = db.sqlite3
 | 
			
		||||
 | 
			
		||||
PROC_NAME = ttime_server
 | 
			
		||||
 | 
			
		||||
# Directory containing migration SQL scripts
 | 
			
		||||
MIGRATIONS_DIR = internal/database/migrations
 | 
			
		||||
SAMPLE_DATA_DIR = internal/database/sample_data
 | 
			
		||||
 | 
			
		||||
# Build target
 | 
			
		||||
build:
 | 
			
		||||
	$(GOBUILD) -o bin/server main.go
 | 
			
		||||
	$(GOBUILD) -o bin/$(PROC_NAME) main.go
 | 
			
		||||
 | 
			
		||||
# Run target
 | 
			
		||||
run: build
 | 
			
		||||
	./bin/server
 | 
			
		||||
	./bin/$(PROC_NAME)
 | 
			
		||||
 | 
			
		||||
watch: build
 | 
			
		||||
	watchexec -c -w . -r make run
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +39,16 @@ clean:
 | 
			
		|||
test: db.sqlite3
 | 
			
		||||
	$(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
 | 
			
		||||
deps:
 | 
			
		||||
	$(GOGET) -v ./...
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,8 @@ type Database interface {
 | 
			
		|||
	SignWeeklyReport(reportId int, projectManagerId int) error
 | 
			
		||||
	IsSiteAdmin(username string) (bool, error)
 | 
			
		||||
	IsProjectManager(username string, projectname string) (bool, error)
 | 
			
		||||
	GetTotalTimePerActivity(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
 | 
			
		||||
| 
						 | 
				
			
			@ -498,6 +499,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
 | 
			
		||||
| 
						 | 
				
			
			@ -537,11 +558,11 @@ func (d *Db) MigrateSampleData() error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Db) GetTotalTimePerActivity(projectName string) (map[string]int, error) {
 | 
			
		||||
 | 
			
		||||
// GetProjectTimes retrieves a map with times per "Activity" for a given project
 | 
			
		||||
func (d *Db) GetProjectTimes(projectName string) (map[string]int, error) {
 | 
			
		||||
	query := `
 | 
			
		||||
        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
 | 
			
		||||
        WHERE projects.name = ?
 | 
			
		||||
    `
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -770,27 +770,90 @@ func TestIsProjectManager(t *testing.T) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTotalTimePerActivity(t *testing.T) {
 | 
			
		||||
	// Initialize your test database connection
 | 
			
		||||
func TestGetProjectTimes(t *testing.T) {
 | 
			
		||||
	// Initialize
 | 
			
		||||
	db, err := setupState()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error("setupState failed:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Run the query to get total time per activity
 | 
			
		||||
	totalTime, err := db.GetTotalTimePerActivity("projecttest")
 | 
			
		||||
	// 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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ska lägga till fler  assertions
 | 
			
		||||
}
 | 
			
		||||
	// 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])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newExpectedTotalTime := map[string]int{
 | 
			
		||||
		"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])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
func TestEnsureManagerOfCreatedProject(t *testing.T) {
 | 
			
		||||
	db, err := setupState()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -824,3 +887,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")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,7 @@ type GlobalState interface {
 | 
			
		|||
	ChangeUserName(c *fiber.Ctx) error      // WIP
 | 
			
		||||
	GetAllUsersProject(c *fiber.Ctx) error  // WIP
 | 
			
		||||
	GetUnsignedReports(c *fiber.Ctx) error  // 
 | 
			
		||||
	UpdateWeeklyReport(c *fiber.Ctx) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "Constructor"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -177,3 +177,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")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,8 +207,8 @@ func (gs *GState) GetAllUsersProject(c *fiber.Ctx) error {
 | 
			
		|||
// @Accept			json
 | 
			
		||||
// @Produce		plain
 | 
			
		||||
// @Param			NewUser	body		types.NewUser	true	"user info"
 | 
			
		||||
// @Success		200		{json}		json			"Successfully prometed user"
 | 
			
		||||
// @Failure		400		{string}	string			"bad request"
 | 
			
		||||
// @Success		200		{json}		json			"Successfully promoted user"
 | 
			
		||||
// @Failure		400		{string}	string			"Bad request"
 | 
			
		||||
// @Failure		401		{string}	string			"Unauthorized"
 | 
			
		||||
// @Failure		500		{string}	string			"Internal server error"
 | 
			
		||||
// @Router			/promoteToAdmin [post]
 | 
			
		||||
| 
						 | 
				
			
			@ -234,33 +234,33 @@ func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error {
 | 
			
		|||
	return c.SendStatus(fiber.StatusOK)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Changes a users name in the database
 | 
			
		||||
// ChangeUserName changes a user's username in the database
 | 
			
		||||
func (gs *GState) ChangeUserName(c *fiber.Ctx) error {
 | 
			
		||||
 | 
			
		||||
	//check token and get username of current user
 | 
			
		||||
	// Check token and get username of current user
 | 
			
		||||
	user := c.Locals("user").(*jwt.Token)
 | 
			
		||||
	claims := user.Claims.(jwt.MapClaims)
 | 
			
		||||
	projectManagerUsername := claims["name"].(string)
 | 
			
		||||
	log.Info(projectManagerUsername)
 | 
			
		||||
	adminUsername := claims["name"].(string)
 | 
			
		||||
	log.Info(adminUsername)
 | 
			
		||||
 | 
			
		||||
	// Extract the necessary parameters from the request
 | 
			
		||||
	data := new(types.NameChange)
 | 
			
		||||
	data := new(types.StrNameChange)
 | 
			
		||||
	if err := c.BodyParser(data); err != nil {
 | 
			
		||||
		log.Info("error parsing username, project or role")
 | 
			
		||||
		log.Info("Error parsing username")
 | 
			
		||||
		return c.Status(400).SendString(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// dubble diping and checcking if current user is
 | 
			
		||||
 | 
			
		||||
	if ismanager, err := gs.Db.IsProjectManager(projectManagerUsername, c.Params(data.Name)); err != nil {
 | 
			
		||||
		log.Warn("Error checking if projectmanager:", err)
 | 
			
		||||
	// Check if the current user is an admin
 | 
			
		||||
	isAdmin, err := gs.Db.IsSiteAdmin(adminUsername)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("Error checking if admin:", err)
 | 
			
		||||
		return c.Status(500).SendString(err.Error())
 | 
			
		||||
	} else if !ismanager {
 | 
			
		||||
		log.Warn("tried changing name when not projectmanager:", err)
 | 
			
		||||
		return c.Status(401).SendString("you can not change name when not projectmanager")
 | 
			
		||||
	} else if !isAdmin {
 | 
			
		||||
		log.Warn("Tried changing name when not admin")
 | 
			
		||||
		return c.Status(401).SendString("You cannot change name unless you are an admin")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Change the user's name within the project in the database
 | 
			
		||||
	if err := gs.Db.ChangeUserName(projectManagerUsername, data.Name); err != nil {
 | 
			
		||||
	// Change the user's name in the database
 | 
			
		||||
	if err := gs.Db.ChangeUserName(data.PrevName, data.NewName); err != nil {
 | 
			
		||||
		return c.Status(500).SendString(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,12 @@ import (
 | 
			
		|||
// @externalDocs.description	OpenAPI
 | 
			
		||||
// @externalDocs.url			https://swagger.io/resources/open-api/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
Main function for starting the server and initializing configurations.
 | 
			
		||||
Reads configuration from file, pretty prints it, connects to the database,
 | 
			
		||||
migrates it, and sets up routes for the server.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conf, err := config.ReadConfigFromFile("config.toml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +108,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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,6 @@ FROM docker.io/golang:alpine as go
 | 
			
		|||
RUN apk add gcompat
 | 
			
		||||
RUN apk add gcc
 | 
			
		||||
RUN apk add musl-dev
 | 
			
		||||
RUN apk add make
 | 
			
		||||
RUN apk add sqlite
 | 
			
		||||
WORKDIR /build
 | 
			
		||||
ADD backend/go.mod backend/go.sum ./
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +23,7 @@ RUN go mod download
 | 
			
		|||
# Add the source code
 | 
			
		||||
ADD backend .
 | 
			
		||||
 | 
			
		||||
RUN make migrate
 | 
			
		||||
 | 
			
		||||
# RUN go build -o server
 | 
			
		||||
RUN go build -o server
 | 
			
		||||
RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o ./server ./main.go
 | 
			
		||||
 | 
			
		||||
# Strip the binary for a smaller image
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +34,7 @@ FROM docker.io/alpine:latest as runner
 | 
			
		|||
RUN adduser -D nonroot
 | 
			
		||||
RUN addgroup nonroot nonroot
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
RUN chown nonroot:nonroot /app
 | 
			
		||||
 | 
			
		||||
# Copy the frontend SPA build into public
 | 
			
		||||
COPY --from=client /build/dist static
 | 
			
		||||
| 
						 | 
				
			
			@ -44,9 +42,6 @@ COPY --from=client /build/dist static
 | 
			
		|||
# Copy the server binary
 | 
			
		||||
COPY --from=go /build/server server
 | 
			
		||||
 | 
			
		||||
# Copy the database
 | 
			
		||||
COPY --from=go /build/db.sqlite3 db.sqlite3
 | 
			
		||||
 | 
			
		||||
# Expose port 8080
 | 
			
		||||
EXPOSE 8080
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ import {
 | 
			
		|||
  User,
 | 
			
		||||
  Project,
 | 
			
		||||
  NewProject,
 | 
			
		||||
  UserProjectMember,
 | 
			
		||||
  WeeklyReport,
 | 
			
		||||
} from "../Types/goTypes";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,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.
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +128,11 @@ interface API {
 | 
			
		|||
   * @returns {Promise<APIResponse<string[]>>} A promise resolving to an API response containing the list of users.
 | 
			
		||||
   */
 | 
			
		||||
  getAllUsers(token: string): Promise<APIResponse<string[]>>;
 | 
			
		||||
  /** Gets all users in a project from name*/
 | 
			
		||||
  getAllUsersProject(
 | 
			
		||||
    projectName: string,
 | 
			
		||||
    token: string,
 | 
			
		||||
  ): Promise<APIResponse<UserProjectMember[]>>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** An instance of the API */
 | 
			
		||||
| 
						 | 
				
			
			@ -288,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",
 | 
			
		||||
| 
						 | 
				
			
			@ -306,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,
 | 
			
		||||
| 
						 | 
				
			
			@ -448,4 +454,34 @@ export const api: API = {
 | 
			
		|||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  //Gets all users in a project
 | 
			
		||||
  async getAllUsersProject(
 | 
			
		||||
    projectName: string,
 | 
			
		||||
    token: string,
 | 
			
		||||
  ): Promise<APIResponse<UserProjectMember[]>> {
 | 
			
		||||
    try {
 | 
			
		||||
      const response = await fetch(`/api/getUsersProject/${projectName}`, {
 | 
			
		||||
        method: "GET",
 | 
			
		||||
        headers: {
 | 
			
		||||
          "Content-Type": "application/json",
 | 
			
		||||
          Authorization: "Bearer " + token,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      if (!response.ok) {
 | 
			
		||||
        return Promise.resolve({
 | 
			
		||||
          success: false,
 | 
			
		||||
          message: "Failed to get users",
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        const data = (await response.json()) as UserProjectMember[];
 | 
			
		||||
        return Promise.resolve({ success: true, data });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      return Promise.resolve({
 | 
			
		||||
        success: false,
 | 
			
		||||
        message: "API is not ok",
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,24 +13,24 @@ function AllTimeReportsInProject(): JSX.Element {
 | 
			
		|||
  const { projectName } = useParams();
 | 
			
		||||
  const [weeklyReports, setWeeklyReports] = useState<WeeklyReport[]>([]);
 | 
			
		||||
 | 
			
		||||
  const getWeeklyReports = async (): Promise<void> => {
 | 
			
		||||
    const token = localStorage.getItem("accessToken") ?? "";
 | 
			
		||||
    const response = await api.getWeeklyReportsForUser(
 | 
			
		||||
      projectName ?? "",
 | 
			
		||||
      token,
 | 
			
		||||
    );
 | 
			
		||||
    console.log(response);
 | 
			
		||||
    if (response.success) {
 | 
			
		||||
      setWeeklyReports(response.data ?? []);
 | 
			
		||||
    } else {
 | 
			
		||||
      console.error(response.message);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Call getProjects when the component mounts
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getWeeklyReports = async (): Promise<void> => {
 | 
			
		||||
      const token = localStorage.getItem("accessToken") ?? "";
 | 
			
		||||
      const response = await api.getWeeklyReportsForUser(
 | 
			
		||||
        projectName ?? "",
 | 
			
		||||
        token,
 | 
			
		||||
      );
 | 
			
		||||
      console.log(response);
 | 
			
		||||
      if (response.success) {
 | 
			
		||||
        setWeeklyReports(response.data ?? []);
 | 
			
		||||
      } else {
 | 
			
		||||
        console.error(response.message);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void getWeeklyReports();
 | 
			
		||||
  }, []);
 | 
			
		||||
  }, [projectName]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,13 +18,11 @@ export default function GetWeeklyReport(): JSX.Element {
 | 
			
		|||
  const [testingTime, setTestingTime] = useState(0);
 | 
			
		||||
 | 
			
		||||
  const token = localStorage.getItem("accessToken") ?? "";
 | 
			
		||||
  const username = localStorage.getItem("username") ?? "";
 | 
			
		||||
  const { projectName } = useParams();
 | 
			
		||||
  const { fetchedWeek } = useParams();
 | 
			
		||||
 | 
			
		||||
  const fetchWeeklyReport = async (): Promise<void> => {
 | 
			
		||||
    const response = await api.getWeeklyReport(
 | 
			
		||||
      username,
 | 
			
		||||
      projectName ?? "",
 | 
			
		||||
      fetchedWeek?.toString() ?? "0",
 | 
			
		||||
      token,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										37
									
								
								frontend/src/Components/GetProjects.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/Components/GetProjects.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
import { Dispatch, useEffect } from "react";
 | 
			
		||||
import { Project } from "../Types/goTypes";
 | 
			
		||||
import { api } from "../API/API";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Gets all projects that user is a member of
 | 
			
		||||
 * @param props - A setStateAction for the array you want to put projects in
 | 
			
		||||
 * @returns {void} Nothing
 | 
			
		||||
 * @example
 | 
			
		||||
 *  const [projects, setProjects] = useState<Project[]>([]);
 | 
			
		||||
 *  GetAllUsers({ setProjectsProp: setProjects });
 | 
			
		||||
 */
 | 
			
		||||
function GetProjects(props: {
 | 
			
		||||
  setProjectsProp: Dispatch<React.SetStateAction<Project[]>>;
 | 
			
		||||
}): void {
 | 
			
		||||
  const setProjects: Dispatch<React.SetStateAction<Project[]>> =
 | 
			
		||||
    props.setProjectsProp;
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const fetchUsers = async (): Promise<void> => {
 | 
			
		||||
      try {
 | 
			
		||||
        const token = localStorage.getItem("accessToken") ?? "";
 | 
			
		||||
        const response = await api.getUserProjects(token);
 | 
			
		||||
        if (response.success) {
 | 
			
		||||
          setProjects(response.data ?? []);
 | 
			
		||||
        } else {
 | 
			
		||||
          console.error("Failed to fetch projects:", response.message);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error("Error fetching projects:", error);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void fetchUsers();
 | 
			
		||||
  }, [setProjects]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default GetProjects;
 | 
			
		||||
							
								
								
									
										37
									
								
								frontend/src/Components/GetUsersInProject.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/Components/GetUsersInProject.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
import { Dispatch, useEffect } from "react";
 | 
			
		||||
import { UserProjectMember } from "../Types/goTypes";
 | 
			
		||||
import { api } from "../API/API";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Gets all projects that user is a member of
 | 
			
		||||
 * @param props - A setStateAction for the array you want to put projects in
 | 
			
		||||
 * @returns {void} Nothing
 | 
			
		||||
 * @example
 | 
			
		||||
 *  const [projects, setProjects] = useState<Project[]>([]);
 | 
			
		||||
 *  GetAllUsers({ setProjectsProp: setProjects });
 | 
			
		||||
 */
 | 
			
		||||
function GetUsersInProject(props: {
 | 
			
		||||
  projectName: string;
 | 
			
		||||
  setUsersProp: Dispatch<React.SetStateAction<UserProjectMember[]>>;
 | 
			
		||||
}): void {
 | 
			
		||||
  const setUsers: Dispatch<React.SetStateAction<UserProjectMember[]>> =
 | 
			
		||||
    props.setUsersProp;
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const fetchUsers = async (): Promise<void> => {
 | 
			
		||||
      try {
 | 
			
		||||
        const token = localStorage.getItem("accessToken") ?? "";
 | 
			
		||||
        const response = await api.getAllUsersProject(props.projectName, token);
 | 
			
		||||
        if (response.success) {
 | 
			
		||||
          setUsers(response.data ?? []);
 | 
			
		||||
        } else {
 | 
			
		||||
          console.error("Failed to fetch projects:", response.message);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error("Error fetching projects:", error);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    void fetchUsers();
 | 
			
		||||
  }, [props.projectName, setUsers]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default GetUsersInProject;
 | 
			
		||||
| 
						 | 
				
			
			@ -60,8 +60,7 @@ export default function NewWeeklyReport(): JSX.Element {
 | 
			
		|||
              type="week"
 | 
			
		||||
              placeholder="Week"
 | 
			
		||||
              onChange={(e) => {
 | 
			
		||||
                const weekNumber = parseInt(e.target.value.split("-W")[1]);
 | 
			
		||||
                setWeek(weekNumber);
 | 
			
		||||
                setWeek(parseInt(e.target.value));
 | 
			
		||||
              }}
 | 
			
		||||
              onKeyDown={(event) => {
 | 
			
		||||
                const keyValue = event.key;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										66
									
								
								frontend/src/Components/ProjectInfoModal.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								frontend/src/Components/ProjectInfoModal.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
import { useState } from "react";
 | 
			
		||||
import Button from "./Button";
 | 
			
		||||
import { UserProjectMember } from "../Types/goTypes";
 | 
			
		||||
import GetUsersInProject from "./GetUsersInProject";
 | 
			
		||||
 | 
			
		||||
function ProjectInfoModal(props: {
 | 
			
		||||
  isVisible: boolean;
 | 
			
		||||
  projectname: string;
 | 
			
		||||
  onClose: () => void;
 | 
			
		||||
  onClick: (username: string) => void;
 | 
			
		||||
}): JSX.Element {
 | 
			
		||||
  const [users, setUsers] = useState<UserProjectMember[]>([]);
 | 
			
		||||
  GetUsersInProject({ projectName: props.projectname, setUsersProp: setUsers });
 | 
			
		||||
  if (!props.isVisible) return <></>;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm 
 | 
			
		||||
      flex justify-center items-center"
 | 
			
		||||
    >
 | 
			
		||||
      <div className="border-4 border-black bg-white p-2 rounded-2xl text-center h-[41vh] w-[40vw] flex flex-col">
 | 
			
		||||
        <div className="pl-20 pr-20">
 | 
			
		||||
          <h1 className="font-bold text-[32px] mb-[20px]">Project members:</h1>
 | 
			
		||||
          <div className="border-2 border-black p-2 rounded-lg text-center overflow-scroll h-[26vh]">
 | 
			
		||||
            <ul className="text-left font-medium space-y-2">
 | 
			
		||||
              <div></div>
 | 
			
		||||
              {users.map((user) => (
 | 
			
		||||
                <li
 | 
			
		||||
                  className="items-start p-1 border-2 border-black rounded-lg bg-orange-200 hover:bg-orange-600 hover:text-slate-100 hover:cursor-pointer"
 | 
			
		||||
                  key={user.Username}
 | 
			
		||||
                  onClick={() => {
 | 
			
		||||
                    props.onClick(user.Username);
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  <span>
 | 
			
		||||
                    Name: {user.Username}
 | 
			
		||||
                    <div></div>
 | 
			
		||||
                    Role: {user.UserRole}
 | 
			
		||||
                  </span>
 | 
			
		||||
                </li>
 | 
			
		||||
              ))}
 | 
			
		||||
            </ul>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="space-x-16">
 | 
			
		||||
          <Button
 | 
			
		||||
            text={"Delete"}
 | 
			
		||||
            onClick={function (): void {
 | 
			
		||||
              //DELETE PROJECT
 | 
			
		||||
            }}
 | 
			
		||||
            type="button"
 | 
			
		||||
          />
 | 
			
		||||
          <Button
 | 
			
		||||
            text={"Close"}
 | 
			
		||||
            onClick={function (): void {
 | 
			
		||||
              props.onClose();
 | 
			
		||||
            }}
 | 
			
		||||
            type="button"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ProjectInfoModal;
 | 
			
		||||
							
								
								
									
										79
									
								
								frontend/src/Components/ProjectListAdmin.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								frontend/src/Components/ProjectListAdmin.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
import { useState } from "react";
 | 
			
		||||
import { NewProject } from "../Types/goTypes";
 | 
			
		||||
import ProjectInfoModal from "./ProjectInfoModal";
 | 
			
		||||
import UserInfoModal from "./UserInfoModal";
 | 
			
		||||
import DeleteUser from "./DeleteUser";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A list of projects for admin manage projects page, that sets an onClick
 | 
			
		||||
 * function for eact project <li> element, which displays a modul with
 | 
			
		||||
 * user info.
 | 
			
		||||
 * @param props - An array of projects to display
 | 
			
		||||
 * @returns {JSX.Element} The project list
 | 
			
		||||
 * @example
 | 
			
		||||
 * const projects: NewProject[] = [{ name: "Project", description: "New" }];
 | 
			
		||||
 * return <ProjectListAdmin projects={projects} />
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export function ProjectListAdmin(props: {
 | 
			
		||||
  projects: NewProject[];
 | 
			
		||||
}): JSX.Element {
 | 
			
		||||
  const [projectModalVisible, setProjectModalVisible] = useState(false);
 | 
			
		||||
  const [projectname, setProjectname] = useState("");
 | 
			
		||||
  const [userModalVisible, setUserModalVisible] = useState(false);
 | 
			
		||||
  const [username, setUsername] = useState("");
 | 
			
		||||
 | 
			
		||||
  const handleClickUser = (username: string): void => {
 | 
			
		||||
    setUsername(username);
 | 
			
		||||
    setUserModalVisible(true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleClickProject = (username: string): void => {
 | 
			
		||||
    setProjectname(username);
 | 
			
		||||
    setProjectModalVisible(true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleCloseProject = (): void => {
 | 
			
		||||
    setProjectname("");
 | 
			
		||||
    setProjectModalVisible(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleCloseUser = (): void => {
 | 
			
		||||
    setProjectname("");
 | 
			
		||||
    setUserModalVisible(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <ProjectInfoModal
 | 
			
		||||
        onClose={handleCloseProject}
 | 
			
		||||
        onClick={handleClickUser}
 | 
			
		||||
        isVisible={projectModalVisible}
 | 
			
		||||
        projectname={projectname}
 | 
			
		||||
      />
 | 
			
		||||
      <UserInfoModal
 | 
			
		||||
        manageMember={true}
 | 
			
		||||
        onClose={handleCloseUser}
 | 
			
		||||
        //TODO: CHANGE TO REMOVE USER FROM PROJECT
 | 
			
		||||
        onDelete={() => DeleteUser}
 | 
			
		||||
        isVisible={userModalVisible}
 | 
			
		||||
        username={username}
 | 
			
		||||
      />
 | 
			
		||||
      <div>
 | 
			
		||||
        <ul className="font-bold underline text-[30px] cursor-pointer padding">
 | 
			
		||||
          {props.projects.map((project) => (
 | 
			
		||||
            <li
 | 
			
		||||
              className="pt-5"
 | 
			
		||||
              key={project.name}
 | 
			
		||||
              onClick={() => {
 | 
			
		||||
                handleClickProject(project.name);
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              {project.name}
 | 
			
		||||
            </li>
 | 
			
		||||
          ))}
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,23 +5,38 @@ import UserProjectListAdmin from "./UserProjectListAdmin";
 | 
			
		|||
 | 
			
		||||
function UserInfoModal(props: {
 | 
			
		||||
  isVisible: boolean;
 | 
			
		||||
  manageMember: boolean;
 | 
			
		||||
  username: string;
 | 
			
		||||
  onClose: () => void;
 | 
			
		||||
  onDelete: (username: string) => void;
 | 
			
		||||
}): JSX.Element {
 | 
			
		||||
  if (!props.isVisible) return <></>;
 | 
			
		||||
 | 
			
		||||
  const ManageUserOrMember = (check: boolean): JSX.Element => {
 | 
			
		||||
    if (check) {
 | 
			
		||||
      return (
 | 
			
		||||
        <Link to="/AdminChangeRole">
 | 
			
		||||
          <p className="mb-[20px] hover:font-bold hover:cursor-pointer underline">
 | 
			
		||||
            (Change Role)
 | 
			
		||||
          </p>
 | 
			
		||||
        </Link>
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
      <Link to="/AdminChangeUserName">
 | 
			
		||||
        <p className="mb-[20px] hover:font-bold hover:cursor-pointer underline">
 | 
			
		||||
          (Change Username)
 | 
			
		||||
        </p>
 | 
			
		||||
      </Link>
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm 
 | 
			
		||||
      flex justify-center items-center"
 | 
			
		||||
    >
 | 
			
		||||
      <div className="border-4 border-black bg-white p-2 rounded-lg text-center">
 | 
			
		||||
      <div className="border-4 border-black bg-white p-2 rounded-lg text-center flex flex-col">
 | 
			
		||||
        <p className="font-bold text-[30px]">{props.username}</p>
 | 
			
		||||
        <Link to="/AdminChangeUserName">
 | 
			
		||||
          <p className="mb-[20px] hover:font-bold hover:cursor-pointer underline">
 | 
			
		||||
            (Change Username)
 | 
			
		||||
          </p>
 | 
			
		||||
        </Link>
 | 
			
		||||
        {ManageUserOrMember(props.manageMember)}
 | 
			
		||||
        <div>
 | 
			
		||||
          <h2 className="font-bold text-[22px] mb-[20px]">
 | 
			
		||||
            Member of these projects:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import { useState } from "react";
 | 
			
		||||
import UserInfoModal from "./UserInfoModal";
 | 
			
		||||
import DeleteUser from "./DeleteUser";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A list of users for admin manage users page, that sets an onClick
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +30,9 @@ export function UserListAdmin(props: { users: string[] }): JSX.Element {
 | 
			
		|||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <UserInfoModal
 | 
			
		||||
        manageMember={false}
 | 
			
		||||
        onClose={handleClose}
 | 
			
		||||
        onDelete={() => DeleteUser}
 | 
			
		||||
        isVisible={modalVisible}
 | 
			
		||||
        username={username}
 | 
			
		||||
      />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,22 @@ import { Link } from "react-router-dom";
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
import { ProjectListAdmin } from "../../Components/ProjectListAdmin";
 | 
			
		||||
import { Project } from "../../Types/goTypes";
 | 
			
		||||
import GetProjects from "../../Components/GetProjects";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
 | 
			
		||||
function AdminManageProjects(): JSX.Element {
 | 
			
		||||
  const content = <></>;
 | 
			
		||||
  const [projects, setProjects] = useState<Project[]>([]);
 | 
			
		||||
  GetProjects({ setProjectsProp: setProjects });
 | 
			
		||||
  const content = (
 | 
			
		||||
    <>
 | 
			
		||||
      <h1 className="font-bold text-[30px] mb-[20px]">Manage Projects</h1>
 | 
			
		||||
      <div className="border-4 border-black bg-white flex flex-col items-center h-[65vh] w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]">
 | 
			
		||||
        <ProjectListAdmin projects={projects} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const buttons = (
 | 
			
		||||
    <>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,13 +14,7 @@ function AdminProjectAddMember(): JSX.Element {
 | 
			
		|||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <Button
 | 
			
		||||
        text="Back"
 | 
			
		||||
        onClick={(): void => {
 | 
			
		||||
          return;
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <BackButton />
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,13 +14,7 @@ function AdminProjectChangeUserRole(): JSX.Element {
 | 
			
		|||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <Button
 | 
			
		||||
        text="Back"
 | 
			
		||||
        onClick={(): void => {
 | 
			
		||||
          return;
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <BackButton />
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,13 +14,7 @@ function AdminProjectManageMembers(): JSX.Element {
 | 
			
		|||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <Button
 | 
			
		||||
        text="Back"
 | 
			
		||||
        onClick={(): void => {
 | 
			
		||||
          return;
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <BackButton />
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,13 +14,7 @@ function AdminProjectPage(): JSX.Element {
 | 
			
		|||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <Button
 | 
			
		||||
        text="Back"
 | 
			
		||||
        onClick={(): void => {
 | 
			
		||||
          return;
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <BackButton />
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,12 @@
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
 | 
			
		||||
function AdminProjectStatistics(): JSX.Element {
 | 
			
		||||
  const content = <></>;
 | 
			
		||||
 | 
			
		||||
  const buttons = (
 | 
			
		||||
    <>
 | 
			
		||||
      <Button
 | 
			
		||||
        text="Back"
 | 
			
		||||
        onClick={(): void => {
 | 
			
		||||
          return;
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <BackButton />
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import BackButton from "../../Components/BackButton";
 | 
			
		||||
import BasicWindow from "../../Components/BasicWindow";
 | 
			
		||||
import Button from "../../Components/Button";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,13 +14,7 @@ function AdminProjectViewMemberInfo(): JSX.Element {
 | 
			
		|||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <Button
 | 
			
		||||
        text="Back"
 | 
			
		||||
        onClick={(): void => {
 | 
			
		||||
          return;
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
      />
 | 
			
		||||
      <BackButton />
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,23 +4,23 @@ body{
 | 
			
		|||
 | 
			
		||||
@keyframes backgroundTransition {
 | 
			
		||||
    0% {
 | 
			
		||||
        background-image: url('src/assets/1.jpg');
 | 
			
		||||
        background-image: url('../assets/1.jpg');
 | 
			
		||||
        animation-timing-function: ease-out;
 | 
			
		||||
    }
 | 
			
		||||
    25% {
 | 
			
		||||
        background-image: url('src/assets/2.jpg');
 | 
			
		||||
        background-image: url('../assets/2.jpg');
 | 
			
		||||
        animation-timing-function: ease-in;
 | 
			
		||||
    }
 | 
			
		||||
    50% {
 | 
			
		||||
        background-image: url('src/assets/3.jpg');
 | 
			
		||||
        background-image: url('../assets/3.jpg');
 | 
			
		||||
        animation-timing-function: ease-out;
 | 
			
		||||
    }
 | 
			
		||||
    75% {
 | 
			
		||||
        background-image: url('src/assets/4.jpg');
 | 
			
		||||
        background-image: url('../assets/4.jpg');
 | 
			
		||||
        animation-timing-function: ease-in;
 | 
			
		||||
    }
 | 
			
		||||
    100% {
 | 
			
		||||
        background-image: url('src/assets/1.jpg');
 | 
			
		||||
        background-image: url('../assets/1.jpg');
 | 
			
		||||
        animation-timing-function: ease-out;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +184,11 @@ export interface PublicUser {
 | 
			
		|||
  userId: string;
 | 
			
		||||
  username: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UserProjectMember {
 | 
			
		||||
	Username: string;
 | 
			
		||||
	UserRole: string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * wrapper type for token
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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": {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								testing.py
									
										
									
									
									
								
							
							
						
						
									
										98
									
								
								testing.py
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -42,6 +42,8 @@ checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager"
 | 
			
		|||
ProjectRoleChangePath = base_url + "/api/ProjectRoleChange"
 | 
			
		||||
getUsersProjectPath = base_url + "/api/getUsersProject"
 | 
			
		||||
getUnsignedReportsPath = base_url + "/api/getUnsignedReports"
 | 
			
		||||
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():
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +372,98 @@ def test_ensure_manager_of_created_project():
 | 
			
		|||
    assert response.json()["isProjectManager"] == True, "User is not project manager"
 | 
			
		||||
    gprint("test_ensure_admin_of_created_project successful")
 | 
			
		||||
 | 
			
		||||
def test_change_user_name():
 | 
			
		||||
    # Register a new user
 | 
			
		||||
    new_user = randomString()
 | 
			
		||||
    register(new_user, "password")
 | 
			
		||||
 | 
			
		||||
    # Log in as the new user
 | 
			
		||||
    token = login(new_user, "password").json()["token"]
 | 
			
		||||
 | 
			
		||||
    # Register a new admin
 | 
			
		||||
    admin_username = randomString()
 | 
			
		||||
    admin_password = "admin_password"
 | 
			
		||||
    dprint(
 | 
			
		||||
        "Registering with username: ", admin_username, " and password: ", admin_password
 | 
			
		||||
    )
 | 
			
		||||
    response = requests.post(
 | 
			
		||||
        registerPath, json={"username": admin_username, "password": admin_password}
 | 
			
		||||
    )
 | 
			
		||||
    admin_token = login(admin_username, admin_password).json()["token"]
 | 
			
		||||
 | 
			
		||||
    # Promote to admin 
 | 
			
		||||
    response = requests.post(
 | 
			
		||||
        promoteToAdminPath,
 | 
			
		||||
        json={"username": admin_username},
 | 
			
		||||
        headers={"Authorization": "Bearer " + admin_token},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Change the user's name
 | 
			
		||||
    response = requests.put(
 | 
			
		||||
        getChangeUserNamePath,
 | 
			
		||||
        json={"prevName": new_user, "newName": randomString()},
 | 
			
		||||
        headers={"Authorization": "Bearer " + admin_token},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Check if the change was successful
 | 
			
		||||
    assert response.status_code == 200, "Change user name failed"
 | 
			
		||||
    gprint("test_change_user_name successful")
 | 
			
		||||
 | 
			
		||||
def test_list_all_users_project():
 | 
			
		||||
    # Log in as a user who is a member of the project
 | 
			
		||||
    admin_username = randomString()
 | 
			
		||||
    admin_password = "admin_password2"
 | 
			
		||||
    dprint(
 | 
			
		||||
        "Registering with username: ", admin_username, " and password: ", admin_password
 | 
			
		||||
    )
 | 
			
		||||
    response = requests.post(
 | 
			
		||||
        registerPath, json={"username": admin_username, "password": admin_password}
 | 
			
		||||
    )
 | 
			
		||||
    dprint(response.text)
 | 
			
		||||
 | 
			
		||||
    # Log in as the admin
 | 
			
		||||
    admin_token = login(admin_username, admin_password).json()["token"]
 | 
			
		||||
    response = requests.post(
 | 
			
		||||
        promoteToAdminPath,
 | 
			
		||||
        json={"username": admin_username},
 | 
			
		||||
        headers={"Authorization": "Bearer " + admin_token},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Make a request to list all users associated with the project
 | 
			
		||||
    response = requests.get(
 | 
			
		||||
        getUsersProjectPath + "/" + projectName,
 | 
			
		||||
        headers={"Authorization": "Bearer " + admin_token},    
 | 
			
		||||
    )
 | 
			
		||||
    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()
 | 
			
		||||
| 
						 | 
				
			
			@ -384,6 +478,8 @@ if __name__ == "__main__":
 | 
			
		|||
    test_get_weekly_reports_user()
 | 
			
		||||
    test_check_if_project_manager()
 | 
			
		||||
    test_ProjectRoleChange()
 | 
			
		||||
    #test_list_all_users_project()
 | 
			
		||||
    test_ensure_manager_of_created_project()
 | 
			
		||||
    test_get_unsigned_reports()
 | 
			
		||||
    test_list_all_users_project()
 | 
			
		||||
    test_change_user_name()
 | 
			
		||||
    test_update_weekly_report()
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue