Files
sale/backend/internal/api/handlers/auth.go
T

323 lines
8.9 KiB
Go

package handlers
import (
"net/http"
"time"
"sale/internal/models"
"sale/internal/schemas"
"sale/internal/utils"
"github.com/gin-gonic/gin"
)
type AuthHandler struct{}
func NewAuthHandler() *AuthHandler {
return &AuthHandler{}
}
func (h *AuthHandler) Register(c *gin.Context) {
var req schemas.RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var existingUser models.User
if err := utils.DB.Where("email = ?", req.Email).First(&existingUser).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "Email already registered"})
return
}
if err := utils.DB.Where("username = ?", req.Username).First(&existingUser).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "Username already taken"})
return
}
hashedPassword, err := utils.HashPassword(req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
return
}
user := models.User{
Username: req.Username,
Email: req.Email,
PasswordHash: hashedPassword,
Role: "user",
InviteCode: utils.GenerateInviteCode(),
IsActive: true,
}
if req.InviteCode != "" {
var referrer models.User
if err := utils.DB.Where("invite_code = ?", req.InviteCode).First(&referrer).Error; err == nil {
user.ReferredBy = &referrer.ID
}
}
if err := utils.DB.Create(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
return
}
if user.ReferredBy != nil {
utils.DB.Model(&models.User{}).Where("id = ?", *user.ReferredBy).
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits + 1"))
}
verifyCode := utils.GenerateVerifyCode()
utils.SendVerifyEmail(req.Email, verifyCode)
token, _ := utils.GenerateToken(user.ID, user.Role)
c.JSON(http.StatusCreated, gin.H{
"token": token,
"user": schemas.UserResponse{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Role: user.Role,
PurchaseCredits: user.PurchaseCredits,
InviteCode: user.InviteCode,
EmailVerified: user.EmailVerified,
},
})
}
func (h *AuthHandler) Login(c *gin.Context) {
var req schemas.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user models.User
if err := utils.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid email or password"})
return
}
if !utils.CheckPassword(req.Password, user.PasswordHash) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid email or password"})
return
}
if !user.IsActive {
c.JSON(http.StatusForbidden, gin.H{"error": "Account is disabled"})
return
}
token, _ := utils.GenerateToken(user.ID, user.Role)
c.JSON(http.StatusOK, gin.H{
"token": token,
"user": schemas.UserResponse{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Role: user.Role,
PurchaseCredits: user.PurchaseCredits,
InviteCode: user.InviteCode,
EmailVerified: user.EmailVerified,
},
})
}
func (h *AuthHandler) ForgotPassword(c *gin.Context) {
var req schemas.ForgotPasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user models.User
if err := utils.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"message": "If the email exists, a verification code has been sent"})
return
}
code := utils.GenerateVerifyCode()
utils.SendResetPasswordEmail(req.Email, code)
c.JSON(http.StatusOK, gin.H{"message": "If the email exists, a verification code has been sent"})
}
func (h *AuthHandler) ResetPassword(c *gin.Context) {
var req schemas.ResetPasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user models.User
if err := utils.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid email"})
return
}
hashedPassword, err := utils.HashPassword(req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
return
}
utils.DB.Model(&user).Update("password_hash", hashedPassword)
c.JSON(http.StatusOK, gin.H{"message": "Password reset successfully"})
}
func (h *AuthHandler) VerifyEmail(c *gin.Context) {
var req schemas.VerifyEmailRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user models.User
if err := utils.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "User not found"})
return
}
utils.DB.Model(&user).Update("email_verified", true)
c.JSON(http.StatusOK, gin.H{"message": "Email verified successfully"})
}
func (h *AuthHandler) GetProfile(c *gin.Context) {
userID := c.GetUint("user_id")
var user models.User
if err := utils.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
c.JSON(http.StatusOK, schemas.UserResponse{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Role: user.Role,
PurchaseCredits: user.PurchaseCredits,
InviteCode: user.InviteCode,
EmailVerified: user.EmailVerified,
})
}
func (h *AuthHandler) UpdateProfile(c *gin.Context) {
userID := c.GetUint("user_id")
var user models.User
if err := utils.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
var updateData map[string]interface{}
if err := c.ShouldBindJSON(&updateData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if username, ok := updateData["username"].(string); ok && username != "" {
user.Username = username
}
utils.DB.Save(&user)
c.JSON(http.StatusOK, gin.H{"message": "Profile updated successfully"})
}
func (h *AuthHandler) ChangePassword(c *gin.Context) {
userID := c.GetUint("user_id")
var req schemas.ChangePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user models.User
if err := utils.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
if !utils.CheckPassword(req.OldPassword, user.PasswordHash) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Old password is incorrect"})
return
}
hashedPassword, _ := utils.HashPassword(req.NewPassword)
utils.DB.Model(&user).Update("password_hash", hashedPassword)
c.JSON(http.StatusOK, gin.H{"message": "Password changed successfully"})
}
func (h *AuthHandler) SendVerifyCode(c *gin.Context) {
userID := c.GetUint("user_id")
var user models.User
if err := utils.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
if user.EmailVerified {
c.JSON(http.StatusBadRequest, gin.H{"error": "Email already verified"})
return
}
code := utils.GenerateVerifyCode()
utils.SendVerifyEmail(user.Email, code)
c.JSON(http.StatusOK, gin.H{"message": "Verification code sent", "expires_at": time.Now().Add(30 * time.Minute)})
}
func (h *AuthHandler) CheckInstalled(c *gin.Context) {
var count int64
utils.DB.Model(&models.User{}).Where("role = ?", "admin").Count(&count)
c.JSON(http.StatusOK, gin.H{"installed": count > 0})
}
func (h *AuthHandler) Install(c *gin.Context) {
var count int64
utils.DB.Model(&models.User{}).Where("role = ?", "admin").Count(&count)
if count > 0 {
c.JSON(http.StatusForbidden, gin.H{"error": "System already installed"})
return
}
var req schemas.InstallRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
hashedPassword, err := utils.HashPassword(req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
return
}
admin := models.User{
Username: req.Username,
Email: req.Email,
PasswordHash: hashedPassword,
Role: "admin",
InviteCode: utils.GenerateInviteCode(),
IsActive: true,
}
if err := utils.DB.Create(&admin).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create admin user"})
return
}
token, _ := utils.GenerateToken(admin.ID, admin.Role)
c.JSON(http.StatusCreated, gin.H{
"token": token,
"user": schemas.UserResponse{
ID: admin.ID,
Username: admin.Username,
Email: admin.Email,
Role: admin.Role,
PurchaseCredits: admin.PurchaseCredits,
InviteCode: admin.InviteCode,
EmailVerified: admin.EmailVerified,
},
})
}