129 lines
3.2 KiB
Go
129 lines
3.2 KiB
Go
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)
|
|
}
|