diff --git a/cmd/api/server.go b/cmd/api/server.go index 80dad39..c67c74d 100644 --- a/cmd/api/server.go +++ b/cmd/api/server.go @@ -165,6 +165,7 @@ func initializeRoutes(engine *gin.Engine) { // Map Mods engine.GET("/v2/map/:id/mods", handlers.CreateHandler(handlers.GetMapMods)) + engine.GET("/v2/map/:id/mods/:mod_id", handlers.CreateHandler(handlers.GetMapMod)) engine.POST("/v2/map/:id/mods", middleware.RequireAuth, handlers.CreateHandler(handlers.SubmitMapMod)) engine.POST("/v2/map/:id/mods/:mod_id/status", middleware.RequireAuth, handlers.CreateHandler(handlers.UpdateMapModStatus)) engine.POST("/v2/map/:id/mods/:mod_id/comment", middleware.RequireAuth, handlers.CreateHandler(handlers.SubmitMapModComment)) diff --git a/db/map_mods.go b/db/map_mods.go index e6d9979..48c7356 100644 --- a/db/map_mods.go +++ b/db/map_mods.go @@ -41,15 +41,18 @@ func (mod *MapMod) AfterFind(*gorm.DB) (err error) { return nil } -// GetMapMods Retrieves map mods for a given map -func GetMapMods(id int) ([]*MapMod, error) { +// GetMapMods retrieves a page of map mods and all replies belonging to those mods. +func GetMapMods(id int, page int, limit int) ([]*MapMod, error) { var mods = make([]*MapMod, 0) result := SQL. Joins("Author"). Preload("Replies"). Preload("Replies.Author"). - Where("map_id = ?", id). + Where("map_mods.map_id = ?", id). + Order("map_mods.id ASC"). + Limit(limit). + Offset(page * limit). Find(&mods) if result.Error != nil { @@ -59,6 +62,22 @@ func GetMapMods(id int) ([]*MapMod, error) { return mods, nil } +// GetMapModsCount gets the total number of mods for a map. +func GetMapModsCount(id int) (int64, error) { + var count int64 + + result := SQL. + Model(&MapMod{}). + Where("map_id = ?", id). + Count(&count) + + if result.Error != nil { + return 0, result.Error + } + + return count, nil +} + // GetModById Gets a mod by its id func GetModById(id int) (*MapMod, error) { var mod *MapMod diff --git a/handlers/limits.go b/handlers/limits.go index 1957de2..e97e5a4 100644 --- a/handlers/limits.go +++ b/handlers/limits.go @@ -13,6 +13,7 @@ const ( defaultUserActivityLimit = 50 defaultUserPlaylistLimit = 50 defaultPlaylistMapsetLimit = 25 + defaultMapModLimit = 20 ) // getQueryLimit returns a requested limit bounded by the endpoint's default limit. diff --git a/handlers/map_mods.go b/handlers/map_mods.go index 48f7893..96f22cf 100644 --- a/handlers/map_mods.go +++ b/handlers/map_mods.go @@ -11,8 +11,8 @@ import ( "strings" ) -// GetMapMods Gets mods for a given map -// Endpoint: GET /v2/maps/:id/mods +// GetMapMods Gets a page of mods for a given map, including all replies to each mod. +// Endpoint: GET /v2/map/:id/mods?page=0&limit=20 func GetMapMods(c *gin.Context) *APIError { id, err := strconv.Atoi(c.Param("id")) @@ -20,13 +20,54 @@ func GetMapMods(c *gin.Context) *APIError { return APIErrorBadRequest("Invalid id") } - mods, err := db.GetMapMods(id) + page, limit := getMapModsPagination(c) + + mods, err := db.GetMapMods(id, page, limit) if err != nil { return APIErrorServerError("Error retrieving map mods from db", err) } - c.JSON(http.StatusOK, gin.H{"mods": mods}) + total, err := db.GetMapModsCount(id) + + if err != nil { + return APIErrorServerError("Error retrieving map mods count from db", err) + } + + c.JSON(http.StatusOK, gin.H{"mods": mods, "total": total}) + return nil +} + +func getMapModsPagination(c *gin.Context) (int, int) { + return getQueryPage(c), getQueryLimit(c, defaultMapModLimit) +} + +// GetMapMod gets a single mod for a map, including all of its replies. +// Endpoint: GET /v2/map/:id/mods/:mod_id +func GetMapMod(c *gin.Context) *APIError { + mapId, err := strconv.Atoi(c.Param("id")) + + if err != nil { + return APIErrorBadRequest("Invalid map id") + } + + modId, err := strconv.Atoi(c.Param("mod_id")) + + if err != nil { + return APIErrorBadRequest("Invalid mod id") + } + + mod, err := db.GetModById(modId) + + if err != nil && err != gorm.ErrRecordNotFound { + return APIErrorServerError("Error retrieving map mod from db", err) + } + + if mod == nil || mod.MapId != mapId { + return APIErrorNotFound("Mod") + } + + c.JSON(http.StatusOK, gin.H{"mod": mod}) return nil }