package server import ( "net/http" "gophergate/internal/db" "github.com/gin-gonic/gin" "golang.org/x/crypto/bcrypt" ) func (s *Server) handleGetUsers(c *gin.Context) { var users []db.User err := s.database.Select(&users, "SELECT id, username, display_name, role, must_change_password, created_at FROM users") if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error())) return } c.JSON(http.StatusOK, SuccessResponse(users)) } type CreateUserRequest struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` DisplayName *string `json:"display_name"` Role *string `json:"role"` } func (s *Server) handleCreateUser(c *gin.Context) { var req CreateUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, ErrorResponse("Invalid request")) return } hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 12) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to hash password")) return } role := "viewer" if req.Role != nil { role = *req.Role } _, err = s.database.Exec("INSERT INTO users (username, password_hash, display_name, role, must_change_password) VALUES (?, ?, ?, ?, 1)", req.Username, string(hash), req.DisplayName, role) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error())) return } c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "User created"})) } type UpdateUserRequest struct { DisplayName *string `json:"display_name"` Role *string `json:"role"` Password *string `json:"password"` MustChangePassword *bool `json:"must_change_password"` } func (s *Server) handleUpdateUser(c *gin.Context) { id := c.Param("id") var req UpdateUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, ErrorResponse("Invalid request")) return } if req.DisplayName != nil { s.database.Exec("UPDATE users SET display_name = ? WHERE id = ?", req.DisplayName, id) } if req.Role != nil { s.database.Exec("UPDATE users SET role = ? WHERE id = ?", req.Role, id) } if req.MustChangePassword != nil { s.database.Exec("UPDATE users SET must_change_password = ? WHERE id = ?", req.MustChangePassword, id) } if req.Password != nil { hash, _ := bcrypt.GenerateFromPassword([]byte(*req.Password), 12) s.database.Exec("UPDATE users SET password_hash = ? WHERE id = ?", string(hash), id) } c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "User updated"})) } func (s *Server) handleDeleteUser(c *gin.Context) { id := c.Param("id") session, _ := c.Get("session") if sess, ok := session.(*Session); ok { var username string s.database.Get(&username, "SELECT username FROM users WHERE id = ?", id) if username == sess.Username { c.JSON(http.StatusBadRequest, ErrorResponse("Cannot delete your own account")) return } } _, err := s.database.Exec("DELETE FROM users WHERE id = ?", id) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error())) return } c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "User deleted"})) }