package authentication import ( "errors" "fmt" "math/rand" "netina/models" "time" "netina/validation" "gorm.io/gorm" ) type GenerateCode struct { DB *gorm.DB } func NewGenerateCode(db *gorm.DB) *GenerateCode { return &GenerateCode{DB: db} } // Generate a random 6-digit code func generateCode() string { rand.Seed(time.Now().UnixNano()) return fmt.Sprintf("%06d", rand.Intn(1000000)) } // CreateLoginCode generates a login code and stores it in the database func (s *GenerateCode) CreateLoginCode(phoneNumber string) (string, error) { var code string var isUnique bool // Try to generate a unique code for !isUnique { code = generateCode() isUnique, _ = s.isCodeUnique(code) } now := time.Now() expiresAt := now.Add(2 * time.Minute) loginCode := &models.LoginCode{ PhoneNumber: phoneNumber, Code: code, CreatedAt: now, ExpiresAt: expiresAt, } if err := validation.ValidateStruct(loginCode); err != nil { return "" , err } if err := s.DB.Create(loginCode).Error; err != nil { return "", err } return code, nil } // Check if the generated code is unique func (s *GenerateCode) isCodeUnique(code string) (bool, error) { var loginCode models.LoginCode if err := s.DB.Where("code = ?", code).First(&loginCode).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return true, nil } return false, err } return false, nil } // VerifyLoginCode verifies the login code and checks if it is still valid func (s *GenerateCode) VerifyLoginCode(phoneNumber, code string) error { var loginCode models.LoginCode // Find the login code if err := s.DB.Where("phone_number = ? AND code = ?", phoneNumber, code).First(&loginCode).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("code not found") } return err } // Check if the code has expired if time.Now().After(loginCode.ExpiresAt) { return errors.New("code expired") } return nil }