From e7b2c86ba72226ff257f7a6a97bf31cff39ec300 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Wed, 3 Jan 2024 15:05:07 +1100 Subject: [PATCH] add delete user endpoint --- README.md | 12 ++++++++++++ controllers/auth.go | 46 +++++++++++++++++++++++++++++++++++++++++---- main.go | 1 + models/user.go | 25 ++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1562d72..88b89d4 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,18 @@ GET `/api/admin/users` This operation can only be performed by a user with a role that is admin enabled. Lists currently defined users. +#### Remove Users +POST `/api/admin/user/delete` + +Data +``` +{ + "userName": "" +} +``` + +This operation can only be performed by a user with a role that is admin enabled. Removes user account corresponding to specified userName. + ### Secrets Operations #### Store diff --git a/controllers/auth.go b/controllers/auth.go index 89024de..9b3e27c 100644 --- a/controllers/auth.go +++ b/controllers/auth.go @@ -15,16 +15,54 @@ import ( ) type RegisterInput struct { - Username string `json:"username" binding:"required"` + UserName string `json:"userName" binding:"required"` Password string `json:"password" binding:"required"` RoleId int `json:"roleid"` } type LoginInput struct { - Username string `json:"username" binding:"required"` + UserName string `json:"userName" binding:"required"` Password string `json:"password" binding:"required"` } +type DeleteInput struct { + UserName string `json:"userName" binding:"required"` +} + +func DeleteUser(c *gin.Context) { + var input DeleteInput + + if err := c.ShouldBindJSON(&input); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + u := models.User{} + u.UserName = input.UserName + + //remove spaces in username + u.UserName = html.EscapeString(strings.TrimSpace(u.UserName)) + + // Confirm user account exists + testUser, _ := models.GetUserByName(u.UserName) + log.Printf("DeleteUser confirming user '%s' account exists\n", u.UserName) + if (models.User{} == testUser) { + err := errors.New("attempt to delete non-existing username '" + u.UserName + "'") + log.Printf("Delete User error : '%s'\n", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } else { + err := u.DeleteUser() + + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"Error deleting user": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "user deletion success"}) + } +} + func Register(c *gin.Context) { var input RegisterInput @@ -35,7 +73,7 @@ func Register(c *gin.Context) { u := models.User{} //u.RoleId = 1 - u.UserName = input.Username + u.UserName = input.UserName u.Password = input.Password // Default to regular user role if not specified @@ -93,7 +131,7 @@ func Login(c *gin.Context) { u := models.User{} - u.UserName = input.Username + u.UserName = input.UserName u.Password = input.Password log.Printf("Login checking username '%s' and password length '%d'\n", u.UserName, len(u.Password)) diff --git a/main.go b/main.go index 2045972..2ce04c1 100644 --- a/main.go +++ b/main.go @@ -250,6 +250,7 @@ func main() { adminOnly.POST("/register", controllers.Register) adminOnly.GET("/roles", controllers.GetRoles) adminOnly.GET("/users", controllers.GetUsers) + adminOnly.GET("/user/delete", controllers.DeleteUser) // Get secrets protected := router.Group("/api/secret") diff --git a/models/user.go b/models/user.go index 5f5b941..d9ff116 100644 --- a/models/user.go +++ b/models/user.go @@ -49,6 +49,31 @@ func (u *User) SaveUser() (*User, error) { return u, nil } +func (u *User) DeleteUser() error { + + // Validate username exists + _, err := GetUserByName(u.UserName) + if err != nil { + log.Printf("DeleteUser error finding user account to remove : '%s'\n", err) + return err + } else { + log.Printf("DeleteUser confirmed user exists, continuing with deletion of user '%s'\n", u.UserName) + result, err := db.NamedExec((`DELETE FROM users WHERE UserName = :UserName`), u) + + if err != nil { + log.Printf("DeleteUser error executing sql delete : '%s'\n", err) + return err + } else { + affected, _ := result.RowsAffected() + id, _ := result.LastInsertId() + log.Printf("DeleteUser returned result id '%d' affecting %d row(s).\n", id, affected) + } + + } + + return nil +} + func VerifyPassword(password, hashedPassword string) error { log.Printf("VerifyPassword comparing input against hashed value '%s'\n", hashedPassword) return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))