package handlers import ( "context" "net/http" "strconv" "strings" "time" "game-admin/internal/models" "github.com/gin-gonic/gin" "github.com/uptrace/bun" ) func (h *GameHandler) ListModules(c *gin.Context) { var modules []models.Module err := h.db.NewSelect(). Model(&modules). OrderExpr("id ASC"). Scan(c) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, modules) } func (h *GameHandler) ListGameModules(c *gin.Context) { gameID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid game id"}) return } exists, err := h.gameExists(c, gameID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if !exists { c.JSON(http.StatusNotFound, gin.H{"error": "Game not found"}) return } modulesByGame, err := h.loadModulesByGameIDs(c, []int64{gameID}) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, modulesByGame[gameID]) } func (h *GameHandler) ConnectModule(c *gin.Context) { gameID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid game id"}) return } var req models.ConnectGameModuleRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } exists, err := h.gameExists(c, gameID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if !exists { c.JSON(http.StatusNotFound, gin.H{"error": "Game not found"}) return } module := new(models.Module) err = h.db.NewSelect(). Model(module). Where(`"key" = ?`, strings.TrimSpace(req.ModuleKey)). Scan(c) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Module not found"}) return } gameModule := &models.GameModule{ GameID: gameID, ModuleID: module.ID, CreatedAt: time.Now(), } _, err = h.db.NewInsert().Model(gameModule).Exec(c) if err != nil { c.JSON(http.StatusConflict, gin.H{"error": "Module already connected to game"}) return } c.JSON(http.StatusCreated, module) } func (h *GameHandler) DisconnectModule(c *gin.Context) { gameID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid game id"}) return } moduleKey := c.Param("module_key") module := new(models.Module) err = h.db.NewSelect(). Model(module). Where(`"key" = ?`, moduleKey). Scan(c) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Module not found"}) return } res, err := h.db.NewDelete(). Model((*models.GameModule)(nil)). Where("game_id = ? AND module_id = ?", gameID, module.ID). Exec(c) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if affected, _ := res.RowsAffected(); affected == 0 { c.JSON(http.StatusNotFound, gin.H{"error": "Module is not connected to game"}) return } c.JSON(http.StatusOK, gin.H{"message": "Module disconnected"}) } func (h *GameHandler) attachModulesToGames(c *gin.Context, games []models.Game) error { if len(games) == 0 { return nil } gameIDs := make([]int64, 0, len(games)) for _, game := range games { gameIDs = append(gameIDs, game.ID) } modulesByGame, err := h.loadModulesByGameIDs(c, gameIDs) if err != nil { return err } for i := range games { games[i].Modules = modulesByGame[games[i].ID] } return nil } func (h *GameHandler) loadModulesByGameIDs(c *gin.Context, gameIDs []int64) (map[int64][]models.Module, error) { var gameModules []models.GameModule err := h.db.NewSelect(). Model(&gameModules). Relation("Module"). Where("gm.game_id IN (?)", bun.In(gameIDs)). OrderExpr("gm.id ASC"). Scan(c) if err != nil { return nil, err } modulesByGame := make(map[int64][]models.Module, len(gameIDs)) for _, gameID := range gameIDs { modulesByGame[gameID] = []models.Module{} } for _, gameModule := range gameModules { if gameModule.Module == nil { continue } modulesByGame[gameModule.GameID] = append(modulesByGame[gameModule.GameID], *gameModule.Module) } return modulesByGame, nil } func (h *GameHandler) gameHasModule(ctx context.Context, gameID int64, moduleKey string) (bool, error) { return h.db.NewSelect(). Model((*models.GameModule)(nil)). Join("JOIN modules AS m ON m.id = gm.module_id"). Where("gm.game_id = ?", gameID). Where(`m."key" = ?`, moduleKey). Exists(ctx) }