timetracker update
This commit is contained in:
@@ -13,7 +13,7 @@ import (
|
||||
"git.ma-al.com/goc_marek/timetracker/app/model"
|
||||
"git.ma-al.com/goc_marek/timetracker/app/service/emailService"
|
||||
constdata "git.ma-al.com/goc_marek/timetracker/app/utils/const_data"
|
||||
"git.ma-al.com/goc_marek/timetracker/app/view"
|
||||
"git.ma-al.com/goc_marek/timetracker/app/utils/responseErrors"
|
||||
|
||||
"github.com/dlclark/regexp2"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
@@ -60,23 +60,23 @@ func (s *AuthService) Login(req *model.LoginRequest) (*model.AuthResponse, strin
|
||||
// Find user by email
|
||||
if err := s.db.Where("email = ?", req.Email).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, "", view.ErrInvalidCredentials
|
||||
return nil, "", responseErrors.ErrInvalidCredentials
|
||||
}
|
||||
return nil, "", fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
// Check if user is active
|
||||
if !user.IsActive {
|
||||
return nil, "", view.ErrUserInactive
|
||||
return nil, "", responseErrors.ErrUserInactive
|
||||
}
|
||||
|
||||
// Check if email is verified
|
||||
if !user.EmailVerified {
|
||||
return nil, "", view.ErrEmailNotVerified
|
||||
return nil, "", responseErrors.ErrEmailNotVerified
|
||||
}
|
||||
|
||||
// Verify password
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
|
||||
return nil, "", view.ErrInvalidCredentials
|
||||
return nil, "", responseErrors.ErrInvalidCredentials
|
||||
}
|
||||
|
||||
// Update last login time
|
||||
@@ -109,17 +109,17 @@ func (s *AuthService) Register(req *model.RegisterRequest) error {
|
||||
// Check if email already exists
|
||||
var existingUser model.Customer
|
||||
if err := s.db.Where("email = ?", req.Email).First(&existingUser).Error; err == nil {
|
||||
return view.ErrEmailExists
|
||||
return responseErrors.ErrEmailExists
|
||||
}
|
||||
|
||||
// Validate passwords match
|
||||
if req.Password != req.ConfirmPassword {
|
||||
return view.ErrPasswordsDoNotMatch
|
||||
return responseErrors.ErrPasswordsDoNotMatch
|
||||
}
|
||||
|
||||
// Validate password strength
|
||||
if err := validatePassword(req.Password); err != nil {
|
||||
return view.ErrInvalidPassword
|
||||
return responseErrors.ErrInvalidPassword
|
||||
}
|
||||
|
||||
// Hash password
|
||||
@@ -176,14 +176,14 @@ func (s *AuthService) CompleteRegistration(req *model.CompleteRegistrationReques
|
||||
var user model.Customer
|
||||
if err := s.db.Where("email_verification_token = ?", req.Token).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, "", view.ErrInvalidVerificationToken
|
||||
return nil, "", responseErrors.ErrInvalidVerificationToken
|
||||
}
|
||||
return nil, "", fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
|
||||
// Check if token is expired
|
||||
if user.EmailVerificationExpires != nil && user.EmailVerificationExpires.Before(time.Now()) {
|
||||
return nil, "", view.ErrVerificationTokenExpired
|
||||
return nil, "", responseErrors.ErrVerificationTokenExpired
|
||||
}
|
||||
|
||||
// Update user - activate account and mark email as verified
|
||||
@@ -283,19 +283,19 @@ func (s *AuthService) ResetPassword(token, newPassword string) error {
|
||||
var user model.Customer
|
||||
if err := s.db.Where("password_reset_token = ?", token).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return view.ErrInvalidResetToken
|
||||
return responseErrors.ErrInvalidResetToken
|
||||
}
|
||||
return fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
|
||||
// Check if token is expired
|
||||
if user.PasswordResetExpires == nil || user.PasswordResetExpires.Before(time.Now()) {
|
||||
return view.ErrResetTokenExpired
|
||||
return responseErrors.ErrResetTokenExpired
|
||||
}
|
||||
|
||||
// Validate new password
|
||||
if err := validatePassword(newPassword); err != nil {
|
||||
return view.ErrInvalidPassword
|
||||
return responseErrors.ErrInvalidPassword
|
||||
}
|
||||
|
||||
// Hash new password
|
||||
@@ -330,14 +330,14 @@ func (s *AuthService) ValidateToken(tokenString string) (*JWTClaims, error) {
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, jwt.ErrTokenExpired) {
|
||||
return nil, view.ErrTokenExpired
|
||||
return nil, responseErrors.ErrTokenExpired
|
||||
}
|
||||
return nil, view.ErrInvalidToken
|
||||
return nil, responseErrors.ErrInvalidToken
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(*JWTClaims)
|
||||
if !ok || !token.Valid {
|
||||
return nil, view.ErrInvalidToken
|
||||
return nil, responseErrors.ErrInvalidToken
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
@@ -352,7 +352,7 @@ func (s *AuthService) RefreshToken(rawToken string) (*model.AuthResponse, string
|
||||
var rt model.RefreshToken
|
||||
if err := s.db.Where("token_hash = ?", tokenHash).First(&rt).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, "", view.ErrInvalidToken
|
||||
return nil, "", responseErrors.ErrInvalidToken
|
||||
}
|
||||
return nil, "", fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
@@ -361,21 +361,21 @@ func (s *AuthService) RefreshToken(rawToken string) (*model.AuthResponse, string
|
||||
if rt.ExpiresAt.Before(time.Now()) {
|
||||
// Clean up expired token
|
||||
s.db.Delete(&rt)
|
||||
return nil, "", view.ErrTokenExpired
|
||||
return nil, "", responseErrors.ErrTokenExpired
|
||||
}
|
||||
|
||||
// Get user from database
|
||||
var user model.Customer
|
||||
if err := s.db.First(&user, rt.CustomerID).Error; err != nil {
|
||||
return nil, "", view.ErrUserNotFound
|
||||
return nil, "", responseErrors.ErrUserNotFound
|
||||
}
|
||||
|
||||
if !user.IsActive {
|
||||
return nil, "", view.ErrUserInactive
|
||||
return nil, "", responseErrors.ErrUserInactive
|
||||
}
|
||||
|
||||
if !user.EmailVerified {
|
||||
return nil, "", view.ErrEmailNotVerified
|
||||
return nil, "", responseErrors.ErrEmailNotVerified
|
||||
}
|
||||
|
||||
// Delete the old refresh token (rotation: one-time use)
|
||||
@@ -420,7 +420,7 @@ func (s *AuthService) GetUserByID(userID uint) (*model.Customer, error) {
|
||||
var user model.Customer
|
||||
if err := s.db.First(&user, userID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, view.ErrUserNotFound
|
||||
return nil, responseErrors.ErrUserNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
@@ -432,7 +432,7 @@ func (s *AuthService) GetUserByEmail(email string) (*model.Customer, error) {
|
||||
var user model.Customer
|
||||
if err := s.db.Where("email = ?", email).First(&user).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, view.ErrUserNotFound
|
||||
return nil, responseErrors.ErrUserNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"git.ma-al.com/goc_marek/timetracker/app/config"
|
||||
"git.ma-al.com/goc_marek/timetracker/app/model"
|
||||
"git.ma-al.com/goc_marek/timetracker/app/utils/responseErrors"
|
||||
"git.ma-al.com/goc_marek/timetracker/app/view"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
@@ -19,17 +20,6 @@ import (
|
||||
|
||||
const googleUserInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
|
||||
|
||||
// GoogleUserInfo represents the user info returned by Google
|
||||
type GoogleUserInfo struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
VerifiedEmail bool `json:"verified_email"`
|
||||
Name string `json:"name"`
|
||||
GivenName string `json:"given_name"`
|
||||
FamilyName string `json:"family_name"`
|
||||
Picture string `json:"picture"`
|
||||
}
|
||||
|
||||
// googleOAuthConfig returns the OAuth2 config for Google
|
||||
func googleOAuthConfig() *oauth2.Config {
|
||||
cfg := config.Get().OAuth.Google
|
||||
@@ -81,7 +71,7 @@ func (s *AuthService) HandleGoogleCallback(code string) (*model.AuthResponse, st
|
||||
}
|
||||
|
||||
if !userInfo.VerifiedEmail {
|
||||
return nil, "", view.ErrEmailNotVerified
|
||||
return nil, "", responseErrors.ErrEmailNotVerified
|
||||
}
|
||||
|
||||
// Find or create user
|
||||
@@ -117,7 +107,7 @@ func (s *AuthService) HandleGoogleCallback(code string) (*model.AuthResponse, st
|
||||
|
||||
// findOrCreateGoogleUser finds an existing user by Google provider ID or email,
|
||||
// or creates a new one.
|
||||
func (s *AuthService) findOrCreateGoogleUser(info *GoogleUserInfo) (*model.Customer, error) {
|
||||
func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model.Customer, error) {
|
||||
var user model.Customer
|
||||
|
||||
// Try to find by provider + provider_id
|
||||
@@ -183,7 +173,7 @@ func (s *AuthService) findOrCreateGoogleUser(info *GoogleUserInfo) (*model.Custo
|
||||
}
|
||||
|
||||
// fetchGoogleUserInfo fetches user info from Google using the provided HTTP client
|
||||
func fetchGoogleUserInfo(client *http.Client) (*GoogleUserInfo, error) {
|
||||
func fetchGoogleUserInfo(client *http.Client) (*view.GoogleUserInfo, error) {
|
||||
resp, err := client.Get(googleUserInfoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -195,7 +185,7 @@ func fetchGoogleUserInfo(client *http.Client) (*GoogleUserInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var userInfo GoogleUserInfo
|
||||
var userInfo view.GoogleUserInfo
|
||||
if err := json.Unmarshal(body, &userInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user