250 lines
6.3 KiB
Go
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)
|
|
}
|