package service import ( "errors" "time" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" "sql-platform/internal/middleware" "sql-platform/internal/model" ) type AuthService struct { DB *gorm.DB } func NewAuthService(db *gorm.DB) *AuthService { return &AuthService{DB: db} } // Login authenticates a user and returns a JWT token func (s *AuthService) Login(username, password string) (*model.User, string, error) { var user model.User if err := s.DB.Where("username = ?", username).First(&user).Error; err != nil { return nil, "", errors.New("invalid username or password") } if !user.IsActive { return nil, "", errors.New("account is disabled") } if err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), []byte(password)); err != nil { return nil, "", errors.New("invalid username or password") } token, err := middleware.GenerateToken(user.ID, user.Username, user.Role) if err != nil { return nil, "", errors.New("failed to generate token") } // Update last login now := time.Now() user.LastLogin = &now s.DB.Model(&user).Update("last_login", now) return &user, token, nil } // Register creates a new user func (s *AuthService) Register(username, displayName, email, phone, password, role string) (*model.User, error) { // Check if username already exists var count int64 s.DB.Model(&model.User{}).Where("username = ?", username).Count(&count) if count > 0 { return nil, errors.New("username already exists") } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return nil, errors.New("failed to hash password") } if role == "" { role = "developer" } user := model.User{ Username: username, DisplayName: displayName, Email: email, Phone: phone, HashedPassword: string(hashedPassword), Role: role, IsActive: true, } if err := s.DB.Create(&user).Error; err != nil { return nil, errors.New("failed to create user") } return &user, nil } // GetUserByID retrieves a user by ID func (s *AuthService) GetUserByID(id uint) (*model.User, error) { var user model.User if err := s.DB.First(&user, id).Error; err != nil { return nil, errors.New("user not found") } return &user, nil } // ListUsers returns all users func (s *AuthService) ListUsers(page, pageSize int) ([]model.User, int64, error) { var users []model.User var total int64 db := s.DB.Model(&model.User{}) db.Count(&total) offset := (page - 1) * pageSize if err := db.Offset(offset).Limit(pageSize).Find(&users).Error; err != nil { return nil, 0, err } return users, total, nil } // UpdateUser updates a user's info func (s *AuthService) UpdateUser(id uint, updates map[string]interface{}) error { return s.DB.Model(&model.User{}).Where("id = ?", id).Updates(updates).Error } // DeleteUser soft-deletes a user func (s *AuthService) DeleteUser(id uint) error { return s.DB.Delete(&model.User{}, id).Error } // ChangePassword changes a user's password func (s *AuthService) ChangePassword(id uint, oldPassword, newPassword string) error { var user model.User if err := s.DB.First(&user, id).Error; err != nil { return errors.New("user not found") } if err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), []byte(oldPassword)); err != nil { return errors.New("incorrect current password") } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { return errors.New("failed to hash password") } return s.DB.Model(&user).Update("hashed_password", string(hashedPassword)).Error } // ResetPassword resets a user's password (admin only) func (s *AuthService) ResetPassword(id uint, newPassword string) error { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { return errors.New("failed to hash password") } return s.DB.Model(&model.User{}).Where("id = ?", id).Update("hashed_password", string(hashedPassword)).Error }