Created edit for users
This commit is contained in:
@@ -20,6 +20,12 @@ type CreateUserDto struct {
|
||||
Role string `json:"role" binding:"required,oneof=admin user"`
|
||||
}
|
||||
|
||||
type UpdateUserDto struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Role string `json:"role,omitempty" binding:"oneof=admin user"`
|
||||
}
|
||||
|
||||
func MapUser(u models.User) UserDto {
|
||||
return UserDto{
|
||||
ID: u.ID,
|
||||
|
||||
@@ -137,3 +137,82 @@ func (h *UsersHandler) GetProfile(c *gin.Context) {
|
||||
}
|
||||
c.JSON(http.StatusOK, dto.MapUser(u))
|
||||
}
|
||||
|
||||
// PUT /users/:id (admin) — update username, password and/or role
|
||||
func (h *UsersHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, _ := strconv.Atoi(idStr)
|
||||
if id <= 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
|
||||
var u models.User
|
||||
if err := h.db.First(&u, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
|
||||
return
|
||||
}
|
||||
|
||||
var req dto.UpdateUserDto
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
updated := false
|
||||
|
||||
// --- Update username ---
|
||||
if strings.TrimSpace(req.Username) != "" {
|
||||
name := strings.TrimSpace(req.Username)
|
||||
if name == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "username cannot be empty"})
|
||||
return
|
||||
}
|
||||
u.Username = name
|
||||
updated = true
|
||||
}
|
||||
|
||||
// --- Update password ---
|
||||
if req.Password != "" {
|
||||
if len(req.Password) < 4 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "password too short"})
|
||||
return
|
||||
}
|
||||
hash, err := crypto.Hash(req.Password, crypto.DefaultArgon2)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "hash error"})
|
||||
return
|
||||
}
|
||||
u.Password = hash
|
||||
updated = true
|
||||
}
|
||||
|
||||
// --- Update role ---
|
||||
if strings.TrimSpace(req.Role) != "" {
|
||||
role := strings.ToLower(strings.TrimSpace(req.Role))
|
||||
if role != "admin" && role != "user" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid role"})
|
||||
return
|
||||
}
|
||||
u.Role = models.Role(role)
|
||||
updated = true
|
||||
}
|
||||
|
||||
if !updated {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "nothing to update"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.db.Save(&u).Error; err != nil {
|
||||
// detect duplicate username
|
||||
e := strings.ToLower(err.Error())
|
||||
if strings.Contains(e, "duplicate") || strings.Contains(e, "unique") || strings.Contains(e, "exists") {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "username already exists"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "update failed"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, dto.MapUser(u))
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func Build(db *gorm.DB, minio *minio.Client, cfg *config.Config) *gin.Engine {
|
||||
r.POST("/auth/change_password", authMW, authH.ChangePassword)
|
||||
|
||||
r.GET("/users/profile", authMW, usersH.Profile)
|
||||
r.POST("/users/:id/set_role", authMW, adminOnly, usersH.SetRole)
|
||||
r.PUT("/users/:id", authMW, adminOnly, usersH.Update)
|
||||
r.GET("/users", authMW, adminOnly, usersH.List)
|
||||
r.POST("/users/create", authMW, adminOnly, usersH.Create)
|
||||
r.DELETE("/users/:id", authMW, adminOnly, usersH.Delete)
|
||||
|
||||
Reference in New Issue
Block a user