cab-backend/internal/handlers/games.go
2026-03-30 21:00:35 +03:00

250 lines
6.3 KiB
Go

package handlers
import (
"net/http"
"strconv"
"time"
"game-admin/internal/config"
"game-admin/internal/models"
"github.com/gin-gonic/gin"
"github.com/uptrace/bun"
)
type GameHandler struct {
db *bun.DB
cfg *config.Config
}
func NewGameHandler(db *bun.DB, cfg *config.Config) *GameHandler {
return &GameHandler{db: db, cfg: cfg}
}
func (h *GameHandler) List(c *gin.Context) {
var games []models.Game
query := h.db.NewSelect().Model(&games).OrderExpr("id DESC")
if s := c.Query("search"); s != "" {
like := "%" + s + "%"
query = query.Where("g.name LIKE ? OR g.slug LIKE ?", like, like)
}
err := query.Scan(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if err := h.attachModulesToGames(c, games); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, games)
}
func (h *GameHandler) GetByID(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid game id"})
return
}
game := new(models.Game)
err = h.db.NewSelect().
Model(game).
Where("g.id = ?", id).
Scan(c)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Game not found"})
return
}
modulesByGame, err := h.loadModulesByGameIDs(c, []int64{game.ID})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
game.Modules = modulesByGame[game.ID]
c.JSON(http.StatusOK, game)
}
func (h *GameHandler) Create(c *gin.Context) {
var req models.CreateGameRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
game := &models.Game{
Name: req.Name,
Slug: req.Slug,
Description: req.Description,
ImageURL: req.ImageURL,
IsActive: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
_, err := h.db.NewInsert().Model(game).Exec(c)
if err != nil {
c.JSON(http.StatusConflict, gin.H{"error": "Game slug already exists"})
return
}
c.JSON(http.StatusCreated, game)
}
func (h *GameHandler) Update(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
var req models.CreateGameRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
_, err := h.db.NewUpdate().Model((*models.Game)(nil)).
Set("name = ?", req.Name).
Set("slug = ?", req.Slug).
Set("description = ?", req.Description).
Set("image_url = ?", req.ImageURL).
Set("updated_at = ?", time.Now()).
Where("id = ?", id).
Exec(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Game updated"})
}
func (h *GameHandler) Delete(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
_, err := h.db.NewDelete().Model((*models.Game)(nil)).Where("id = ?", id).Exec(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Game deleted"})
}
// ─── User-Game connections ──────────────────────────────────
func (h *GameHandler) ConnectGame(c *gin.Context) {
userID, _ := strconv.ParseInt(c.Param("id"), 10, 64)
var req models.ConnectGameRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
ug := &models.UserGame{
UserID: userID,
GameID: req.GameID,
Balance: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
_, err := h.db.NewInsert().Model(ug).Exec(c)
if err != nil {
c.JSON(http.StatusConflict, gin.H{"error": "Game already connected"})
return
}
c.JSON(http.StatusCreated, ug)
}
func (h *GameHandler) DisconnectGame(c *gin.Context) {
userID, _ := strconv.ParseInt(c.Param("id"), 10, 64)
gameID, _ := strconv.ParseInt(c.Param("game_id"), 10, 64)
_, err := h.db.NewDelete().Model((*models.UserGame)(nil)).
Where("user_id = ? AND game_id = ?", userID, gameID).
Exec(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Game disconnected"})
}
func (h *GameHandler) UserGames(c *gin.Context) {
userID, _ := strconv.ParseInt(c.Param("id"), 10, 64)
var userGames []models.UserGame
err := h.db.NewSelect().Model(&userGames).
Relation("Game").
Where("ug.user_id = ?", userID).
Scan(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, userGames)
}
func (h *GameHandler) TopUp(c *gin.Context) {
ugID, _ := strconv.ParseInt(c.Param("ug_id"), 10, 64)
adminID, _ := c.Get("user_id")
var req models.TopUpRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
tx, err := h.db.BeginTx(c, nil)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer tx.Rollback()
// Update balance
_, err = tx.NewUpdate().Model((*models.UserGame)(nil)).
Set("balance = balance + ?", req.Amount).
Set("updated_at = ?", time.Now()).
Where("id = ?", ugID).
Exec(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Log transaction
txn := &models.BalanceTransaction{
UserGameID: ugID,
Amount: req.Amount,
Type: "topup",
Comment: req.Comment,
AdminID: adminID.(int64),
CreatedAt: time.Now(),
}
_, err = tx.NewInsert().Model(txn).Exec(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if err := tx.Commit(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Balance topped up", "transaction": txn})
}
func (h *GameHandler) Transactions(c *gin.Context) {
ugID, _ := strconv.ParseInt(c.Param("ug_id"), 10, 64)
var txns []models.BalanceTransaction
err := h.db.NewSelect().Model(&txns).
Where("user_game_id = ?", ugID).
OrderExpr("id DESC").
Scan(c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, txns)
}