From 54b1522db519d3328e31541f9fbecee89ca8336a Mon Sep 17 00:00:00 2001 From: AzenKain Date: Thu, 28 May 2026 02:46:48 +0700 Subject: [PATCH] feat: implement battle replay controller, service, and routes with Swagger documentation --- docs/docs.go | 48 +++++++++++++++++++ docs/swagger.json | 48 +++++++++++++++++++ docs/swagger.yaml | 32 +++++++++++++ .../controllers/battleReplayController.go | 39 +++++++++++++++ internal/dtos/request/battle_replay.go | 5 ++ internal/routes/battleReplayRoute.go | 1 + internal/services/battleReplayService.go | 25 ++++++++++ 7 files changed, 198 insertions(+) create mode 100644 internal/dtos/request/battle_replay.go diff --git a/docs/docs.go b/docs/docs.go index ec5580c..e84819a 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -450,6 +450,54 @@ const docTemplate = `{ } } }, + "/battle-replays/geometries": { + "get": { + "description": "Get battle replays grouped by geometry IDs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "BattleReplays" + ], + "summary": "Get battle replays by geometry IDs", + "parameters": [ + { + "minItems": 1, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "csv", + "name": "geometry_ids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse" + } + } + } + } + }, "/battle-replays/geometry/{geometryId}": { "get": { "description": "Get all battle replays associated with a specific geometry", diff --git a/docs/swagger.json b/docs/swagger.json index 77c8597..edda57e 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -443,6 +443,54 @@ } } }, + "/battle-replays/geometries": { + "get": { + "description": "Get battle replays grouped by geometry IDs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "BattleReplays" + ], + "summary": "Get battle replays by geometry IDs", + "parameters": [ + { + "minItems": 1, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "csv", + "name": "geometry_ids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse" + } + } + } + } + }, "/battle-replays/geometry/{geometryId}": { "get": { "description": "Get all battle replays associated with a specific geometry", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index f49414e..03c6257 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1070,6 +1070,38 @@ paths: summary: Get battle replay by ID tags: - BattleReplays + /battle-replays/geometries: + get: + consumes: + - application/json + description: Get battle replays grouped by geometry IDs + parameters: + - collectionFormat: csv + in: query + items: + type: string + minItems: 1 + name: geometry_ids + required: true + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/history-api_internal_dtos_response.CommonResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/history-api_internal_dtos_response.CommonResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/history-api_internal_dtos_response.CommonResponse' + summary: Get battle replays by geometry IDs + tags: + - BattleReplays /battle-replays/geometry/{geometryId}: get: consumes: diff --git a/internal/controllers/battleReplayController.go b/internal/controllers/battleReplayController.go index 4bfb93e..c0cf03e 100644 --- a/internal/controllers/battleReplayController.go +++ b/internal/controllers/battleReplayController.go @@ -2,8 +2,10 @@ package controllers import ( "context" + "history-api/internal/dtos/request" "history-api/internal/dtos/response" "history-api/internal/services" + "history-api/pkg/validator" "time" "github.com/gofiber/fiber/v3" @@ -70,3 +72,40 @@ func (h *BattleReplayController) GetBattleReplaysByGeometryId(c fiber.Ctx) error Data: res, }) } + +// GetBattleReplaysByGeometryIDs handles fetching battle replays by a list of geometry IDs. +// @Summary Get battle replays by geometry IDs +// @Description Get battle replays grouped by geometry IDs +// @Tags BattleReplays +// @Accept json +// @Produce json +// @Param query query request.GetBattleReplaysByGeometryIDsDto true "Query Parameters" +// @Success 200 {object} response.CommonResponse +// @Failure 400 {object} response.CommonResponse +// @Failure 500 {object} response.CommonResponse +// @Router /battle-replays/geometries [get] +func (h *BattleReplayController) GetBattleReplaysByGeometryIDs(c fiber.Ctx) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + dto := &request.GetBattleReplaysByGeometryIDsDto{} + if err := validator.ValidateQueryDto(c, dto); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(response.CommonResponse{ + Status: false, + Errors: err, + }) + } + + res, err := h.service.GetByGeometryIDs(ctx, dto) + if err != nil { + return c.Status(err.Code).JSON(response.CommonResponse{ + Status: false, + Message: err.Message, + }) + } + + return c.Status(fiber.StatusOK).JSON(response.CommonResponse{ + Status: true, + Data: res, + }) +} diff --git a/internal/dtos/request/battle_replay.go b/internal/dtos/request/battle_replay.go new file mode 100644 index 0000000..e0644ca --- /dev/null +++ b/internal/dtos/request/battle_replay.go @@ -0,0 +1,5 @@ +package request + +type GetBattleReplaysByGeometryIDsDto struct { + GeometryIDs []string `json:"geometry_ids" query:"geometry_ids" validate:"required,min=1,dive,uuid"` +} diff --git a/internal/routes/battleReplayRoute.go b/internal/routes/battleReplayRoute.go index 0f8a606..3715c9e 100644 --- a/internal/routes/battleReplayRoute.go +++ b/internal/routes/battleReplayRoute.go @@ -8,6 +8,7 @@ import ( func BattleReplayRoutes(router fiber.Router, battleReplayController *controllers.BattleReplayController) { br := router.Group("/battle-replays") + br.Get("/geometries", battleReplayController.GetBattleReplaysByGeometryIDs) br.Get("/geometry/:geometryId", battleReplayController.GetBattleReplaysByGeometryId) br.Get("/:id", battleReplayController.GetBattleReplayById) } diff --git a/internal/services/battleReplayService.go b/internal/services/battleReplayService.go index 1a4931c..b49a680 100644 --- a/internal/services/battleReplayService.go +++ b/internal/services/battleReplayService.go @@ -2,6 +2,7 @@ package services import ( "context" + "history-api/internal/dtos/request" "history-api/internal/dtos/response" "history-api/internal/models" "history-api/internal/repositories" @@ -13,6 +14,7 @@ import ( type BattleReplayService interface { GetByID(ctx context.Context, id string) (*response.BattleReplayResponse, *fiber.Error) GetByGeometryID(ctx context.Context, geometryID string) ([]*response.BattleReplayResponse, *fiber.Error) + GetByGeometryIDs(ctx context.Context, req *request.GetBattleReplaysByGeometryIDsDto) (map[string][]*response.BattleReplayResponse, *fiber.Error) } type battleReplayService struct { @@ -52,3 +54,26 @@ func (s *battleReplayService) GetByGeometryID(ctx context.Context, geometryID st return models.BattleReplaysEntityToResponse(replays), nil } + +func (s *battleReplayService) GetByGeometryIDs(ctx context.Context, req *request.GetBattleReplaysByGeometryIDsDto) (map[string][]*response.BattleReplayResponse, *fiber.Error) { + replays, err := s.battleReplayRepo.GetByGeometryIDs(ctx, req.GeometryIDs) + if err != nil { + return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get battle replays") + } + + result := make(map[string][]*response.BattleReplayResponse) + for _, idStr := range req.GeometryIDs { + result[idStr] = make([]*response.BattleReplayResponse, 0) + } + + for _, replay := range replays { + if replay != nil { + geomID := replay.GeometryID + if _, exists := result[geomID]; exists { + result[geomID] = append(result[geomID], replay.ToResponse()) + } + } + } + + return result, nil +}