summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhaturatu <taro@eyes4you.org>2025-10-12 22:57:23 +0900
committerhaturatu <taro@eyes4you.org>2025-10-12 22:57:23 +0900
commit6515a6fd2b2d29a8f363c906148f3abf7cf982e9 (patch)
treed6e0f27c3520c39250b6c36b021f8fea68e81807
parentf01c229995c0352abe048bb654130f2d548747e4 (diff)
fix(api): admin api
-rw-r--r--cmd/server/main.go14
-rw-r--r--handlers/admin.go51
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)
+}