package handlers import ( "git.itzana.me/strafesnet/go-grpc/maps_extended" "git.itzana.me/strafesnet/maps-service/pkg/public_api/dto" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "net/http" "strconv" ) // MapHandler handles HTTP requests related to maps. type MapHandler struct { *Handler } // NewMapHandler creates a new MapHandler with the provided options. func NewMapHandler(options ...HandlerOption) (*MapHandler, error) { baseHandler, err := NewHandler(options...) if err != nil { return nil, err } return &MapHandler{ Handler: baseHandler, }, nil } // @Summary Get map by ID // @Description Get a specific map by its ID // @Tags maps // @Produce json // @Security ApiKeyAuth // @Param id path int true "Map ID" // @Success 200 {object} dto.Response[dto.Map] // @Failure 404 {object} dto.Error "Map not found" // @Failure default {object} dto.Error "General error response" // @Router /map/{id} [get] func (h *MapHandler) Get(ctx *gin.Context) { // Extract map ID from path parameter id := ctx.Param("id") mapID, err := strconv.ParseInt(id, 10, 64) if err != nil { ctx.JSON(http.StatusBadRequest, dto.Error{ Error: "Invalid map ID format", }) return } // Call the gRPC service mapData, err := maps_extended.NewMapsServiceClient(h.mapsClient).Get(ctx, &maps_extended.MapId{ ID: mapID, }) if err != nil { statusCode := http.StatusInternalServerError errorMessage := "Failed to get map" // Check if it's a "not found" error if status.Code(err) == codes.NotFound { statusCode = http.StatusNotFound errorMessage = "Map not found" } ctx.JSON(statusCode, dto.Error{ Error: errorMessage, }) log.WithError(err).Error( "Failed to get map", ) return } // Convert gRPC MapResponse object to dto.Map object var mapDto dto.Map result := mapDto.FromGRPC(mapData) // Return the map data ctx.JSON(http.StatusOK, dto.Response[dto.Map]{ Data: *result, }) } // @Summary List maps // @Description Get a list of maps // @Tags maps // @Produce json // @Security ApiKeyAuth // @Param page_size query int false "Page size (max 100)" default(10) minimum(1) maximum(100) // @Param page_number query int false "Page number" default(1) minimum(1) // @Param filter query dto.MapFilter false "Map filter parameters" // @Success 200 {object} dto.PagedResponse[dto.Map] // @Failure default {object} dto.Error "General error response" // @Router /map [get] func (h *MapHandler) List(ctx *gin.Context) { // Extract and constrain pagination parameters query := struct { PageSize int `form:"page_size,default=10" binding:"min=1,max=100"` PageNumber int `form:"page_number,default=1" binding:"min=1"` SortBy int `form:"sort_by,default=0" binding:"min=0,max=3"` }{} if err := ctx.ShouldBindQuery(&query); err != nil { ctx.JSON(http.StatusBadRequest, dto.Error{ Error: err.Error(), }) return } // Get list filter var filter dto.MapFilter if err := ctx.ShouldBindQuery(&filter); err != nil { ctx.JSON(http.StatusBadRequest, dto.Error{ Error: err.Error(), }) return } // Call the gRPC service mapList, err := maps_extended.NewMapsServiceClient(h.mapsClient).List(ctx, &maps_extended.ListRequest{ Filter: &maps_extended.MapFilter{ GameID: filter.GameID, }, Page: &maps_extended.Pagination{ Size: uint32(query.PageSize), Number: uint32(query.PageNumber), }, }) if err != nil { ctx.JSON(http.StatusInternalServerError, dto.Error{ Error: "Failed to list maps", }) log.WithError(err).Error( "Failed to list maps", ) return } // Convert gRPC MapResponse objects to dto.Map objects dtoMaps := make([]dto.Map, len(mapList.Maps)) for i, m := range mapList.Maps { var mapDto dto.Map dtoMaps[i] = *mapDto.FromGRPC(m) } // Return the paged response ctx.JSON(http.StatusOK, dto.PagedResponse[dto.Map]{ Data: dtoMaps, Pagination: dto.Pagination{ Page: query.PageNumber, PageSize: query.PageSize, }, }) }