2024-03-17 16:55:40 +01:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
"ttime/internal/types"
|
|
|
|
|
2024-03-18 23:38:50 +01:00
|
|
|
"github.com/gofiber/fiber/v2/log"
|
|
|
|
|
2024-03-17 16:55:40 +01:00
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Register is a simple handler that registers a new user
|
|
|
|
//
|
2024-03-19 00:27:31 +01:00
|
|
|
// @Summary Register
|
2024-03-17 16:55:40 +01:00
|
|
|
// @Description Register a new user
|
|
|
|
// @Tags User
|
|
|
|
// @Accept json
|
2024-03-18 20:05:47 +01:00
|
|
|
// @Produce plain
|
2024-03-18 23:21:49 +01:00
|
|
|
// @Param NewUser body types.NewUser true "User to register"
|
|
|
|
// @Success 200 {string} string "User added"
|
|
|
|
// @Failure 400 {string} string "Bad request"
|
|
|
|
// @Failure 500 {string} string "Internal server error"
|
2024-03-18 20:05:47 +01:00
|
|
|
// @Router /register [post]
|
2024-03-17 16:55:40 +01:00
|
|
|
func (gs *GState) Register(c *fiber.Ctx) error {
|
|
|
|
u := new(types.NewUser)
|
|
|
|
if err := c.BodyParser(u); err != nil {
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Warn("Error parsing body")
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(400).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("Adding user:", u.Username)
|
2024-03-17 16:55:40 +01:00
|
|
|
if err := gs.Db.AddUser(u.Username, u.Password); err != nil {
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Warn("Error adding user:", err)
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(500).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("User added:", u.Username)
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(200).SendString("User added")
|
|
|
|
}
|
|
|
|
|
|
|
|
// This path should obviously be protected in the future
|
|
|
|
// UserDelete deletes a user from the database
|
2024-03-18 22:40:51 +01:00
|
|
|
//
|
2024-03-19 00:27:31 +01:00
|
|
|
// @Summary UserDelete
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Description UserDelete deletes a user from the database
|
|
|
|
// @Tags User
|
|
|
|
// @Accept json
|
|
|
|
// @Produce plain
|
2024-03-18 23:21:49 +01:00
|
|
|
// @Success 200 {string} string "User deleted"
|
|
|
|
// @Failure 403 {string} string "You can only delete yourself"
|
|
|
|
// @Failure 500 {string} string "Internal server error"
|
|
|
|
// @Failure 401 {string} string "Unauthorized"
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Router /userdelete/{username} [delete]
|
2024-03-17 16:55:40 +01:00
|
|
|
func (gs *GState) UserDelete(c *fiber.Ctx) error {
|
|
|
|
// Read from path parameters
|
|
|
|
username := c.Params("username")
|
|
|
|
|
|
|
|
// Read username from Locals
|
|
|
|
auth_username := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)["name"].(string)
|
|
|
|
|
|
|
|
if username != auth_username {
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Info("User tried to delete another user")
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(403).SendString("You can only delete yourself")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := gs.Db.RemoveUser(username); err != nil {
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Warn("Error deleting user:", err)
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(500).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Info("User deleted:", username)
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(200).SendString("User deleted")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Login is a simple login handler that returns a JWT token
|
2024-03-18 22:40:51 +01:00
|
|
|
//
|
|
|
|
// @Summary login
|
|
|
|
// @Description logs the user in and returns a jwt token
|
|
|
|
// @Tags User
|
|
|
|
// @Accept json
|
2024-03-18 23:21:49 +01:00
|
|
|
// @Param NewUser body types.NewUser true "login info"
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Produce plain
|
2024-03-18 23:21:49 +01:00
|
|
|
// @Success 200 Token types.Token "Successfully signed token for user"
|
|
|
|
// @Failure 400 {string} string "Bad request"
|
|
|
|
// @Failure 401 {string} string "Unauthorized"
|
|
|
|
// @Failure 500 {string} string "Internal server error"
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Router /login [post]
|
2024-03-17 16:55:40 +01:00
|
|
|
func (gs *GState) Login(c *fiber.Ctx) error {
|
|
|
|
// The body type is identical to a NewUser
|
2024-03-18 22:40:51 +01:00
|
|
|
|
2024-03-17 16:55:40 +01:00
|
|
|
u := new(types.NewUser)
|
|
|
|
if err := c.BodyParser(u); err != nil {
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Warn("Error parsing body")
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(400).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Info("Username logging in:", u.Username)
|
2024-03-17 16:55:40 +01:00
|
|
|
if !gs.Db.CheckUser(u.Username, u.Password) {
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("User not found")
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.SendStatus(fiber.StatusUnauthorized)
|
|
|
|
}
|
|
|
|
|
2024-03-19 23:54:54 +01:00
|
|
|
isAdmin, err := gs.Db.IsSiteAdmin(u.Username)
|
|
|
|
if err != nil {
|
|
|
|
log.Info("Error checking admin status:", err)
|
|
|
|
return c.Status(500).SendString(err.Error())
|
2024-03-20 12:50:04 +01:00
|
|
|
}
|
2024-03-17 16:55:40 +01:00
|
|
|
// Create the Claims
|
|
|
|
claims := jwt.MapClaims{
|
|
|
|
"name": u.Username,
|
2024-03-19 23:54:54 +01:00
|
|
|
"admin": isAdmin,
|
2024-03-17 16:55:40 +01:00
|
|
|
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create token
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("Token created for user:", u.Username)
|
2024-03-17 16:55:40 +01:00
|
|
|
|
|
|
|
// Generate encoded token and send it as response.
|
|
|
|
t, err := token.SignedString([]byte("secret"))
|
|
|
|
if err != nil {
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Warn("Error signing token")
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
|
2024-03-17 19:24:13 +01:00
|
|
|
println("Successfully signed token for user:", u.Username)
|
2024-03-18 22:40:51 +01:00
|
|
|
return c.JSON(types.Token{Token: t})
|
2024-03-17 16:55:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoginRenew is a simple handler that renews the token
|
2024-03-18 22:40:51 +01:00
|
|
|
//
|
2024-03-19 00:27:31 +01:00
|
|
|
// @Summary LoginRenews
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Description renews the users token
|
2024-03-19 00:27:31 +01:00
|
|
|
// @Security bererToken
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Tags User
|
|
|
|
// @Accept json
|
|
|
|
// @Produce plain
|
2024-03-18 23:21:49 +01:00
|
|
|
// @Success 200 Token types.Token "Successfully signed token for user"
|
|
|
|
// @Failure 401 {string} string "Unauthorized"
|
|
|
|
// @Failure 500 {string} string "Internal server error"
|
2024-03-18 22:40:51 +01:00
|
|
|
// @Router /loginerenew [post]
|
2024-03-17 16:55:40 +01:00
|
|
|
func (gs *GState) LoginRenew(c *fiber.Ctx) error {
|
|
|
|
user := c.Locals("user").(*jwt.Token)
|
2024-03-19 00:00:18 +01:00
|
|
|
|
|
|
|
log.Info("Renewing token for user:", user.Claims.(jwt.MapClaims)["name"])
|
|
|
|
|
2024-03-17 16:55:40 +01:00
|
|
|
claims := user.Claims.(jwt.MapClaims)
|
|
|
|
claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
|
|
|
|
renewed := jwt.MapClaims{
|
|
|
|
"name": claims["name"],
|
|
|
|
"admin": claims["admin"],
|
|
|
|
"exp": claims["exp"],
|
|
|
|
}
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, renewed)
|
|
|
|
t, err := token.SignedString([]byte("secret"))
|
|
|
|
if err != nil {
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Warn("Error signing token")
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
2024-03-19 00:00:18 +01:00
|
|
|
|
|
|
|
log.Info("Successfully renewed token for user:", user.Claims.(jwt.MapClaims)["name"])
|
2024-03-18 22:40:51 +01:00
|
|
|
return c.JSON(types.Token{Token: t})
|
2024-03-17 16:55:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListAllUsers is a handler that returns a list of all users in the application database
|
2024-03-18 23:21:49 +01:00
|
|
|
//
|
2024-03-19 00:27:31 +01:00
|
|
|
// @Summary ListsAllUsers
|
2024-03-18 23:21:49 +01:00
|
|
|
// @Description lists all users
|
|
|
|
// @Tags User
|
|
|
|
// @Accept json
|
|
|
|
// @Produce plain
|
|
|
|
// @Success 200 {json} json "Successfully signed token for user"
|
|
|
|
// @Failure 401 {string} string "Unauthorized"
|
|
|
|
// @Failure 500 {string} string "Internal server error"
|
|
|
|
// @Router /users/all [get]
|
2024-03-17 16:55:40 +01:00
|
|
|
func (gs *GState) ListAllUsers(c *fiber.Ctx) error {
|
|
|
|
// Get all users from the database
|
|
|
|
users, err := gs.Db.GetAllUsersApplication()
|
|
|
|
if err != nil {
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Info("Error getting users from db:", err) // Debug print
|
2024-03-17 16:55:40 +01:00
|
|
|
return c.Status(500).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
2024-03-19 00:00:18 +01:00
|
|
|
log.Info("Returning all users")
|
2024-03-17 16:55:40 +01:00
|
|
|
// Return the list of users as JSON
|
|
|
|
return c.JSON(users)
|
|
|
|
}
|
2024-03-18 14:47:15 +01:00
|
|
|
|
2024-03-20 13:03:43 +01:00
|
|
|
func (gs *GState) GetAllUsersProject(c *fiber.Ctx) error {
|
|
|
|
// Get all users from a project
|
|
|
|
projectName := c.Params("projectName")
|
|
|
|
users, err := gs.Db.GetAllUsersProject(projectName)
|
|
|
|
if err != nil {
|
|
|
|
log.Info("Error getting users from project:", err) // Debug print
|
|
|
|
return c.Status(500).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Returning all users")
|
|
|
|
// Return the list of users as JSON
|
|
|
|
return c.JSON(users)
|
|
|
|
}
|
|
|
|
|
2024-03-20 12:50:04 +01:00
|
|
|
// @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]
|
2024-03-18 14:47:15 +01:00
|
|
|
func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error {
|
|
|
|
// Extract the username from the request body
|
|
|
|
var newUser types.NewUser
|
|
|
|
if err := c.BodyParser(&newUser); err != nil {
|
|
|
|
return c.Status(400).SendString("Bad request")
|
|
|
|
}
|
|
|
|
username := newUser.Username
|
|
|
|
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("Promoting user to admin:", username) // Debug print
|
2024-03-18 14:47:15 +01:00
|
|
|
|
|
|
|
// Promote the user to a site admin in the database
|
|
|
|
if err := gs.Db.PromoteToAdmin(username); err != nil {
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("Error promoting user to admin:", err) // Debug print
|
2024-03-18 14:47:15 +01:00
|
|
|
return c.Status(500).SendString(err.Error())
|
|
|
|
}
|
|
|
|
|
2024-03-18 23:38:50 +01:00
|
|
|
log.Info("User promoted to admin successfully:", username) // Debug print
|
2024-03-18 14:47:15 +01:00
|
|
|
|
|
|
|
// Return a success message
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
|
|
}
|
2024-03-20 12:50:04 +01:00
|
|
|
|
|
|
|
// 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)
|
2024-03-20 16:55:55 +01:00
|
|
|
return c.Status(401).SendString("you can not change name when not projectmanager")
|
2024-03-20 12:50:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|