package handlers import ( "net/http" "time" "game-admin/internal/config" "game-admin/internal/middleware" "game-admin/internal/models" "github.com/gin-gonic/gin" "github.com/uptrace/bun" "golang.org/x/crypto/bcrypt" ) type AuthHandler struct { db *bun.DB cfg *config.Config } func NewAuthHandler(db *bun.DB, cfg *config.Config) *AuthHandler { return &AuthHandler{db: db, cfg: cfg} } func (h *AuthHandler) Login(c *gin.Context) { var req models.LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } user := new(models.User) err := h.db.NewSelect().Model(user).Where("email = ?", req.Email).Scan(c) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) return } if !user.IsActive { c.JSON(http.StatusForbidden, gin.H{"error": "Account deactivated"}) return } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) return } token, err := middleware.GenerateToken(user, h.cfg) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"}) return } c.JSON(http.StatusOK, gin.H{ "token": token, "user": user, }) } func (h *AuthHandler) Register(c *gin.Context) { var req models.RegisterRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Determine role from invite code role := models.RoleUser if req.InviteCode != "" { invite := new(models.InviteLink) err := h.db.NewSelect().Model(invite).Where("code = ?", req.InviteCode).Scan(c) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid invite code"}) return } if invite.UsedCount >= invite.MaxUses { c.JSON(http.StatusBadRequest, gin.H{"error": "Invite code exhausted"}) return } if invite.ExpiresAt != nil && invite.ExpiresAt.Before(time.Now()) { c.JSON(http.StatusBadRequest, gin.H{"error": "Invite code expired"}) return } role = invite.Role // Increment usage invite.UsedCount++ _, _ = h.db.NewUpdate().Model(invite).Column("used_count").WherePK().Exec(c) } hashed, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not hash password"}) return } user := &models.User{ Email: req.Email, Username: req.Username, Password: string(hashed), Role: role, IsActive: true, CreatedAt: time.Now(), UpdatedAt: time.Now(), } _, err = h.db.NewInsert().Model(user).Exec(c) if err != nil { c.JSON(http.StatusConflict, gin.H{"error": "User already exists"}) return } token, _ := middleware.GenerateToken(user, h.cfg) c.JSON(http.StatusCreated, gin.H{ "token": token, "user": user, }) } func (h *AuthHandler) Me(c *gin.Context) { userID, _ := c.Get("user_id") user := new(models.User) err := h.db.NewSelect().Model(user).Where("id = ?", userID).Scan(c) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) return } c.JSON(http.StatusOK, user) }