Merge branch 'BumBranch' into gruppDM

This commit is contained in:
Davenludd 2024-03-20 15:21:26 +01:00
commit 847073c6f8
8 changed files with 182 additions and 31 deletions

View file

@ -3,6 +3,7 @@ package database
import ( import (
"embed" "embed"
"errors" "errors"
"fmt"
"path/filepath" "path/filepath"
"ttime/internal/types" "ttime/internal/types"
@ -19,12 +20,14 @@ type Database interface {
PromoteToAdmin(username string) error PromoteToAdmin(username string) error
GetUserId(username string) (int, error) GetUserId(username string) (int, error)
AddProject(name string, description string, username string) error AddProject(name string, description string, username string) error
DeleteProject(name string, username string) error
Migrate() error Migrate() error
MigrateSampleData() error MigrateSampleData() error
GetProjectId(projectname string) (int, error) GetProjectId(projectname string) (int, error)
AddWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error AddWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error
AddUserToProject(username string, projectname string, role string) error AddUserToProject(username string, projectname string, role string) error
ChangeUserRole(username string, projectname string, role string) error ChangeUserRole(username string, projectname string, role string) error
ChangeUserName(username string, newname string) error
GetAllUsersProject(projectname string) ([]UserProjectMember, error) GetAllUsersProject(projectname string) ([]UserProjectMember, error)
GetAllUsersApplication() ([]string, error) GetAllUsersApplication() ([]string, error)
GetProjectsForUser(username string) ([]types.Project, error) GetProjectsForUser(username string) ([]types.Project, error)
@ -65,11 +68,14 @@ const addWeeklyReport = `WITH UserLookup AS (SELECT id FROM users WHERE username
VALUES ((SELECT id FROM ProjectLookup), (SELECT id FROM UserLookup),?, ?, ?, ?, ?, ?, ?);` VALUES ((SELECT id FROM ProjectLookup), (SELECT id FROM UserLookup),?, ?, ?, ?, ?, ?, ?);`
const addUserToProject = "INSERT INTO user_roles (user_id, project_id, p_role) VALUES (?, ?, ?)" // WIP const addUserToProject = "INSERT INTO user_roles (user_id, project_id, p_role) VALUES (?, ?, ?)" // WIP
const changeUserRole = "UPDATE user_roles SET p_role = ? WHERE user_id = ? AND project_id = ?" const changeUserRole = "UPDATE user_roles SET p_role = ? WHERE user_id = ? AND project_id = ?"
const changeUserName = "UPDATE user SET username = ? WHERE user_id = ?" // WIP
const getProjectsForUser = `SELECT p.id, p.name, p.description FROM projects p const getProjectsForUser = `SELECT p.id, p.name, p.description FROM projects p
JOIN user_roles ur ON p.id = ur.project_id JOIN user_roles ur ON p.id = ur.project_id
JOIN users u ON ur.user_id = u.id JOIN users u ON ur.user_id = u.id
WHERE u.username = ?` WHERE u.username = ?`
const deleteProject = `DELETE FROM projects
WHERE id = ? AND owner_username = ?`
// DbConnect connects to the database // DbConnect connects to the database
func DbConnect(dbpath string) Database { func DbConnect(dbpath string) Database {
@ -165,6 +171,20 @@ func (d *Db) ChangeUserRole(username string, projectname string, role string) er
return err3 return err3
} }
// ChangeUserRole changes the role of a user within a project.
func (d *Db) ChangeUserName(username string, newname string) error {
// Get the user ID
var userid int
userid, err := d.GetUserId(username)
if err != nil {
panic(err)
}
// Execute the SQL query to change the user's role
_, err2 := d.Exec(changeUserName, username, userid)
return err2
}
// GetUserRole retrieves the role of a user within a project. // GetUserRole retrieves the role of a user within a project.
func (d *Db) GetUserRole(username string, projectname string) (string, error) { func (d *Db) GetUserRole(username string, projectname string) (string, error) {
var role string var role string
@ -225,6 +245,21 @@ func (d *Db) AddProject(name string, description string, username string) error
return err return err
} }
func (d *Db) DeleteProject(projectID string, username string) error {
tx := d.MustBegin()
_, err := tx.Exec(deleteProject, projectID, username)
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
return fmt.Errorf("error rolling back transaction: %v, delete error: %v", rollbackErr, err)
}
panic(err)
}
return err
}
func (d *Db) GetAllUsersProject(projectname string) ([]UserProjectMember, error) { func (d *Db) GetAllUsersProject(projectname string) ([]UserProjectMember, error) {
// Define the SQL query to fetch users and their roles for a given project // Define the SQL query to fetch users and their roles for a given project
query := ` query := `

View file

@ -22,23 +22,12 @@ type GlobalState interface {
PromoteToAdmin(c *fiber.Ctx) error PromoteToAdmin(c *fiber.Ctx) error
GetWeeklyReportsUserHandler(c *fiber.Ctx) error GetWeeklyReportsUserHandler(c *fiber.Ctx) error
IsProjectManagerHandler(c *fiber.Ctx) error IsProjectManagerHandler(c *fiber.Ctx) error
// GetProject(c *fiber.Ctx) error // To get a specific project DeleteProject(c *fiber.Ctx) error // To delete a project // WIP
// UpdateProject(c *fiber.Ctx) error // To update a project
// DeleteProject(c *fiber.Ctx) error // To delete a project
// CreateTask(c *fiber.Ctx) error // To create a new task
// GetTasks(c *fiber.Ctx) error // To get all tasks
// GetTask(c *fiber.Ctx) error // To get a specific task
// UpdateTask(c *fiber.Ctx) error // To update a task
// DeleteTask(c *fiber.Ctx) error // To delete a task
// CreateCollection(c *fiber.Ctx) error // To create a new collection
// GetCollections(c *fiber.Ctx) error // To get all collections
// GetCollection(c *fiber.Ctx) error // To get a specific collection
// UpdateCollection(c *fiber.Ctx) error // To update a collection
// DeleteCollection(c *fiber.Ctx) error // To delete a collection
// SignCollection(c *fiber.Ctx) error // To sign a collection
ListAllUsers(c *fiber.Ctx) error // To get a list of all users in the application database ListAllUsers(c *fiber.Ctx) error // To get a list of all users in the application database
ListAllUsersProject(c *fiber.Ctx) error // To get a list of all users for a specific project ListAllUsersProject(c *fiber.Ctx) error // To get a list of all users for a specific project
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
GetAllUsersProject(c *fiber.Ctx) error // WIP
} }
// "Constructor" // "Constructor"

View file

@ -30,6 +30,18 @@ func (gs *GState) CreateProject(c *fiber.Ctx) error {
return c.Status(200).SendString("Project added") return c.Status(200).SendString("Project added")
} }
func (gs *GState) DeleteProject(c *fiber.Ctx) error {
projectID := c.Params("projectID")
username := c.Params("username")
if err := gs.Db.DeleteProject(projectID, username); err != nil {
return c.Status(500).SendString((err.Error()))
}
return c.Status(200).SendString("Project deleted")
}
// GetUserProjects returns all projects that the user is a member of // GetUserProjects returns all projects that the user is a member of
func (gs *GState) GetUserProjects(c *fiber.Ctx) error { func (gs *GState) GetUserProjects(c *fiber.Ctx) error {
// First we get the username from the token // First we get the username from the token
@ -118,6 +130,31 @@ func (gs *GState) ListAllUsersProject(c *fiber.Ctx) error {
return c.Status(400).SendString("No project name provided") return c.Status(400).SendString("No project name provided")
} }
// Get the user token
userToken := c.Locals("user").(*jwt.Token)
claims := userToken.Claims.(jwt.MapClaims)
username := claims["name"].(string)
// Check if the user is a project manager for the specified project
isManager, err := gs.Db.IsProjectManager(username, projectName)
if err != nil {
log.Info("Error checking project manager status:", err)
return c.Status(500).SendString(err.Error())
}
// If the user is not a project manager, check if the user is a site admin
if !isManager {
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 manager nor a site admin:", username)
return c.Status(403).SendString("User is neither a project manager nor a site admin")
}
}
// Get all users associated with the project from the database // Get all users associated with the project from the database
users, err := gs.Db.GetAllUsersProject(projectName) users, err := gs.Db.GetAllUsersProject(projectName)
if err != nil { if err != nil {
@ -189,3 +226,8 @@ func (gs *GState) IsProjectManagerHandler(c *fiber.Ctx) error {
// Return the result as JSON // Return the result as JSON
return c.JSON(map[string]bool{"isProjectManager": isManager}) return c.JSON(map[string]bool{"isProjectManager": isManager})
} }
func (gs *GState) CreateTask(c *fiber.Ctx) error {
return nil
}

View file

@ -105,7 +105,7 @@ func (gs *GState) Login(c *fiber.Ctx) error {
if err != nil { if err != nil {
log.Info("Error checking admin status:", err) log.Info("Error checking admin status:", err)
return c.Status(500).SendString(err.Error()) return c.Status(500).SendString(err.Error())
} }
// Create the Claims // Create the Claims
claims := jwt.MapClaims{ claims := jwt.MapClaims{
"name": u.Username, "name": u.Username,
@ -187,17 +187,31 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error {
return c.JSON(users) return c.JSON(users)
} }
// @Summary PromoteToAdmin func (gs *GState) GetAllUsersProject(c *fiber.Ctx) error {
// @Description promote chosen user to admin // Get all users from a project
// @Tags User projectName := c.Params("projectName")
// @Accept json users, err := gs.Db.GetAllUsersProject(projectName)
// @Produce plain if err != nil {
// @Param NewUser body types.NewUser true "user info" log.Info("Error getting users from project:", err) // Debug print
// @Success 200 {json} json "Successfully prometed user" return c.Status(500).SendString(err.Error())
// @Failure 400 {string} string "bad request" }
// @Failure 401 {string} string "Unauthorized"
// @Failure 500 {string} string "Internal server error" log.Info("Returning all users")
// @Router /promoteToAdmin [post] // Return the list of users as JSON
return c.JSON(users)
}
// @Summary PromoteToAdmin
// @Description promote chosen user to admin
// @Tags User
// @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"
// @Failure 401 {string} string "Unauthorized"
// @Failure 500 {string} string "Internal server error"
// @Router /promoteToAdmin [post]
func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error { func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error {
// Extract the username from the request body // Extract the username from the request body
var newUser types.NewUser var newUser types.NewUser
@ -219,3 +233,37 @@ func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error {
// Return a success message // Return a success message
return c.SendStatus(fiber.StatusOK) return c.SendStatus(fiber.StatusOK)
} }
// Changes a users name in the database
func (gs *GState) ChangeUserName(c *fiber.Ctx) error {
//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)
// Extract the necessary parameters from the request
data := new(types.NameChange)
if err := c.BodyParser(data); err != nil {
log.Info("error parsing username, project or role")
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)
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")
}
// Change the user's name within the project in the database
if err := gs.Db.ChangeUserName(projectManagerUsername, data.Name); err != nil {
return c.Status(500).SendString(err.Error())
}
// Return a success message
return c.SendStatus(fiber.StatusOK)
}

View file

@ -19,3 +19,8 @@ type RoleChange struct {
Username string `json:"username"` Username string `json:"username"`
Projectname string `json:"projectname"` Projectname string `json:"projectname"`
} }
type NameChange struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
}

View file

@ -87,16 +87,21 @@ func main() {
server.Get("/api/getUserProjects", gs.GetUserProjects) server.Get("/api/getUserProjects", gs.GetUserProjects)
server.Post("/api/loginrenew", gs.LoginRenew) server.Post("/api/loginrenew", gs.LoginRenew)
server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches
server.Post("/api/project", gs.CreateProject) server.Delete("api/project/:projectID", gs.DeleteProject) // WIP
server.Post("/api/project", gs.CreateProject) // WIP
server.Get("/api/project/:projectId", gs.GetProject) server.Get("/api/project/:projectId", gs.GetProject)
server.Get("/api/project/getAllUsers", gs.GetAllUsersProject)
server.Get("/api/getWeeklyReport", gs.GetWeeklyReport) server.Get("/api/getWeeklyReport", gs.GetWeeklyReport)
server.Post("/api/signReport", gs.SignReport) server.Post("/api/signReport", gs.SignReport)
server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) server.Put("/api/addUserToProject", gs.AddUserToProjectHandler)
server.Put("/api/changeUserName", gs.ChangeUserName)
server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) server.Post("/api/promoteToAdmin", gs.PromoteToAdmin)
server.Get("/api/users/all", gs.ListAllUsers) server.Get("/api/users/all", gs.ListAllUsers)
server.Get("/api/getWeeklyReportsUser", gs.GetWeeklyReportsUserHandler) server.Get("/api/getWeeklyReportsUser", gs.GetWeeklyReportsUserHandler)
server.Get("api/checkIfProjectManager", gs.IsProjectManagerHandler) server.Get("api/checkIfProjectManager", gs.IsProjectManagerHandler)
server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange) server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange)
server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject)
// 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))
if err != nil { if err != nil {

View file

@ -49,7 +49,7 @@ interface API {
week: string, week: string,
token: string, token: string,
): Promise<APIResponse<WeeklyReport>>; ): Promise<APIResponse<WeeklyReport>>;
getWeeklyReportsForProject( getWeeklyReportsForUser(
username: string, username: string,
projectName: string, projectName: string,
token: string, token: string,
@ -276,19 +276,18 @@ export const api: API = {
} }
}, },
async getWeeklyReportsForProject( async getWeeklyReportsForUser(
username: string, username: string,
projectName: string, projectName: string,
token: string, token: string,
): Promise<APIResponse<WeeklyReport[]>> { ): Promise<APIResponse<WeeklyReport[]>> {
try { try {
const response = await fetch("/api/getWeeklyReportsUser", { const response = await fetch(`/api/getWeeklyReportsUser?username=${username}&projectName=${projectName}`, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: "Bearer " + token, Authorization: "Bearer " + token,
}, },
body: JSON.stringify({ username, projectName }),
}); });
if (!response.ok) { if (!response.ok) {

View file

@ -40,6 +40,7 @@ getUserProjectsPath = base_url + "/api/getUserProjects"
getWeeklyReportsUserPath = base_url + "/api/getWeeklyReportsUser" getWeeklyReportsUserPath = base_url + "/api/getWeeklyReportsUser"
checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager" checkIfProjectManagerPath = base_url + "/api/checkIfProjectManager"
ProjectRoleChangePath = base_url + "/api/ProjectRoleChange" ProjectRoleChangePath = base_url + "/api/ProjectRoleChange"
getUsersProjectPath = base_url + "/api/getUsersProject"
#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():
@ -338,7 +339,33 @@ def test_check_if_project_manager():
assert response.status_code == 200, "Check if project manager failed" assert response.status_code == 200, "Check if project manager failed"
gprint("test_check_if_project_manager successful") gprint("test_check_if_project_manager 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")
if __name__ == "__main__": if __name__ == "__main__":
@ -354,3 +381,4 @@ if __name__ == "__main__":
test_get_weekly_reports_user() test_get_weekly_reports_user()
test_check_if_project_manager() test_check_if_project_manager()
test_ProjectRoleChange() test_ProjectRoleChange()
test_list_all_users_project()