From c9a32e8889707d0344bf6c7d2d69f61084060596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Jurmanovi=C4=87?= Date: Sun, 22 Mar 2026 12:16:40 +0100 Subject: [PATCH] feat: batch update config endpoint --- local/controller/config.go | 50 ++++++++++++++++++++++++++++++++++ local/model/config.go | 8 ++++++ local/service/config.go | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/local/controller/config.go b/local/controller/config.go index 30123af..1c316f0 100644 --- a/local/controller/config.go +++ b/local/controller/config.go @@ -2,6 +2,7 @@ package controller import ( "acc-server-manager/local/middleware" + "acc-server-manager/local/model" "acc-server-manager/local/service" "acc-server-manager/local/utl/common" "acc-server-manager/local/utl/error_handler" @@ -34,6 +35,7 @@ func NewConfigController(as *service.ConfigService, routeGroups *common.RouteGro configGroup := routeGroups.Config configGroup.Use(auth.Authenticate) + configGroup.Patch("/", ac.UpdateAllConfigs) configGroup.Put("/:file", ac.UpdateConfig) configGroup.Get("/:file", ac.GetConfig) configGroup.Get("/", ac.GetConfigs) @@ -41,6 +43,54 @@ func NewConfigController(as *service.ConfigService, routeGroups *common.RouteGro return ac } +// updateAllConfigs updates all configuration files +// +// @Summary Bulk update all server configuration files +// @Description Update multiple ACC server configuration files in one request. Null or omitted sections are skipped. +// @Tags Server Configuration +// @Accept json +// @Produce json +// @Param id path string true "Server ID (UUID format)" +// @Param restart query bool false "Restart the server after update" +// @Param override query bool false "Override instead of merging with existing config" +// @Param content body model.ConfigurationsUpdateRequest true "Configuration sections to update (null sections are skipped)" +// @Success 200 {array} model.Config "List of updated config audit records" +// @Failure 400 {object} error_handler.ErrorResponse "Invalid request or JSON format" +// @Failure 401 {object} error_handler.ErrorResponse "Unauthorized" +// @Failure 403 {object} error_handler.ErrorResponse "Insufficient permissions" +// @Failure 404 {object} error_handler.ErrorResponse "Server not found" +// @Failure 500 {object} error_handler.ErrorResponse "Internal server error" +// @Security BearerAuth +// @Router /server/{id}/config [patch] +func (ac *ConfigController) UpdateAllConfigs(c *fiber.Ctx) error { + restart := c.QueryBool("restart") + serverID := c.Params("id") + + if _, err := uuid.Parse(serverID); err != nil { + return ac.errorHandler.HandleUUIDError(c, "server ID") + } + + c.Locals("serverId", serverID) + + var req model.ConfigurationsUpdateRequest + if err := c.BodyParser(&req); err != nil { + return ac.errorHandler.HandleParsingError(c, err) + } + + configs, err := ac.service.UpdateAllConfigs(c, &req) + if err != nil { + return ac.errorHandler.HandleServiceError(c, err) + } + + if restart { + if _, err := ac.apiService.ServiceControlRestartServer(c); err != nil { + logging.ErrorWithContext("CONFIG_RESTART", "Failed to restart server after bulk config update: %v", err) + } + } + + return c.JSON(configs) +} + // updateConfig returns Config // // @Summary Update server configuration file diff --git a/local/model/config.go b/local/model/config.go index 8ea2306..c8570c6 100644 --- a/local/model/config.go +++ b/local/model/config.go @@ -40,6 +40,14 @@ type Configurations struct { Settings ServerSettings `json:"settings"` } +type ConfigurationsUpdateRequest struct { + Configuration *map[string]interface{} `json:"configuration"` + AssistRules *map[string]interface{} `json:"assistRules"` + Event *map[string]interface{} `json:"event"` + EventRules *map[string]interface{} `json:"eventRules"` + Settings *map[string]interface{} `json:"settings"` +} + type ServerSettings struct { ServerName string `json:"serverName"` AdminPassword string `json:"adminPassword"` diff --git a/local/service/config.go b/local/service/config.go index 09363f1..b632854 100644 --- a/local/service/config.go +++ b/local/service/config.go @@ -91,6 +91,62 @@ func (as *ConfigService) SetServerService(serverService *ServerService) { // context.Context: Application context // Returns: // string: Application version +func (as *ConfigService) UpdateAllConfigs(ctx *fiber.Ctx, req *model.ConfigurationsUpdateRequest) ([]*model.Config, error) { + serverID := ctx.Locals("serverId").(string) + override := ctx.QueryBool("override", false) + + serverUUID, err := uuid.Parse(serverID) + if err != nil { + logging.Error("Invalid server ID format: %v", err) + return nil, fmt.Errorf("invalid server ID format") + } + + server, err := as.serverRepository.GetByID(ctx.UserContext(), serverUUID) + if err != nil { + logging.Error("Server not found") + return nil, fmt.Errorf("server not found") + } + + type configEntry struct { + fileName string + body *map[string]interface{} + } + + entries := []configEntry{ + {ConfigurationJson, req.Configuration}, + {AssistRulesJson, req.AssistRules}, + {EventJson, req.Event}, + {EventRulesJson, req.EventRules}, + {SettingsJson, req.Settings}, + } + + var results []*model.Config + for _, entry := range entries { + if entry.body == nil { + continue + } + oldDataUTF8, newData, err := as.updateConfigFiles(ctx.UserContext(), server, entry.fileName, entry.body, override) + if err != nil { + return nil, err + } + result := as.repository.UpdateConfig(ctx.UserContext(), &model.Config{ + ServerID: serverUUID, + ConfigFile: entry.fileName, + OldConfig: string(oldDataUTF8), + NewConfig: string(newData), + ChangedAt: time.Now(), + }) + results = append(results, result) + } + + if len(results) > 0 { + as.configCache.InvalidateServerCache(serverID) + as.serverService.StartAccServerRuntime(server) + } + + return results, nil +} + func (as *ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface{}) (*model.Config, error) { serverID := ctx.Locals("serverId").(string) configFile := ctx.Params("file")