diff options
| author | haturatu <taro@eyes4you.org> | 2025-10-12 22:57:23 +0900 |
|---|---|---|
| committer | haturatu <taro@eyes4you.org> | 2025-10-12 22:57:23 +0900 |
| commit | 6515a6fd2b2d29a8f363c906148f3abf7cf982e9 (patch) | |
| tree | d6e0f27c3520c39250b6c36b021f8fea68e81807 | |
| parent | f01c229995c0352abe048bb654130f2d548747e4 (diff) | |
fix(api): admin api
| -rw-r--r-- | cmd/server/main.go | 14 | ||||
| -rw-r--r-- | handlers/admin.go | 51 |
2 files changed, 62 insertions, 3 deletions
diff --git a/cmd/server/main.go b/cmd/server/main.go index 89d17bc..196164e 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -112,13 +112,21 @@ func main() { mux.HandleFunc("/api/auth/token", handlers.TokenHandler) // --- Protected API Endpoints (for Admin UI, protected by SessionAuth) --- - adminUsersAPI := http.HandlerFunc(handlers.GetUsersHandler) + adminCreateUserAPI := http.HandlerFunc(handlers.CreateUserHandler) + adminUsersAPI := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + adminCreateUserAPI.ServeHTTP(w, r) + } else { + getUsersHandler.ServeHTTP(w, r) + } + }) + adminUpdateRoleAPI := http.HandlerFunc(handlers.UpdateUserRoleHandler) adminDeleteUserAPI := http.HandlerFunc(handlers.DeleteUserHandler) adminSetStatusAPI := http.HandlerFunc(handlers.SetUserActiveStatusHandler) - mux.Handle(config.Paths.AdminUsersAPI, middleware.SessionAuth(middleware.AdminMiddleware(adminUsersAPI))) - mux.Handle(config.Paths.AdminUsersAPI+"/", middleware.SessionAuth(middleware.AdminMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mux.Handle(config.Paths.AdminUsersAPI, middleware.BearerAuth(middleware.AdminMiddleware(adminUsersAPI))) + mux.Handle(config.Paths.AdminUsersAPI+"/", middleware.BearerAuth(middleware.AdminMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { path := r.URL.Path switch { case strings.HasSuffix(path, "/role") && r.Method == http.MethodPost: diff --git a/handlers/admin.go b/handlers/admin.go index 61519fa..8f302c0 100644 --- a/handlers/admin.go +++ b/handlers/admin.go @@ -205,3 +205,54 @@ func SetUserActiveStatusHandler(w http.ResponseWriter, r *http.Request) { logging.SecurityLog.Info("ADMIN ACTION", "action", "set_active_status", "performed_by", adminUsername, "target_user_id", id, "new_status", req.IsActive, "ip", ip) w.WriteHeader(http.StatusOK) } + +// CreateUserHandler handles creating a new user by an admin. +func CreateUserHandler(w http.ResponseWriter, r *http.Request) { + ip := logging.GetClientIP(r) + + var reqBody struct { + Username string `json:"username"` + Password string `json:"password"` + Role string `json:"role"` + } + + if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { + http.Error(w, "Invalid request body", http.StatusBadRequest) + return + } + + // Default role to "user" if not provided or invalid + if reqBody.Role != "admin" && reqBody.Role != "user" { + reqBody.Role = "user" + } + + // Validate password policy + if ok, message := utils.ValidatePassword(reqBody.Password); !ok { + http.Error(w, message, http.StatusBadRequest) + return + } + + existingUser, err := models.GetUserByUsername(reqBody.Username) + if err != nil { + logging.AppLog.Error("Error checking username during admin user creation", "error", err, "ip", ip) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + if existingUser != nil { + http.Error(w, "Username is already taken", http.StatusConflict) + return + } + + user, err := models.CreateUser(reqBody.Username, reqBody.Password, reqBody.Role) + if err != nil { + logging.AppLog.Error("Failed to create user via admin API", "error", err, "username", reqBody.Username, "ip", ip) + http.Error(w, "Failed to create user", http.StatusInternalServerError) + return + } + + logging.SecurityLog.Info("USER CREATED BY ADMIN", "username", user.Username, "role", user.Role, "ip", ip) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(user) +} |
