From 2e645f3368a03fcdfeb4a4c5547041ab611bcce5 Mon Sep 17 00:00:00 2001 From: Wiktor Date: Tue, 7 Apr 2026 13:36:43 +0200 Subject: [PATCH] fix: google provider auth --- app/delivery/web/api/restricted/customer.go | 8 +- app/repos/customerRepo/customerRepo.go | 81 +++++++++++++++++++++ app/repos/rolesRepo/rolesRepo.go | 22 ++++++ app/service/authService/auth.go | 18 +++-- app/service/authService/google_oauth.go | 30 ++++++-- 5 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 app/repos/rolesRepo/rolesRepo.go diff --git a/app/delivery/web/api/restricted/customer.go b/app/delivery/web/api/restricted/customer.go index 6f953b3..7c04b7e 100644 --- a/app/delivery/web/api/restricted/customer.go +++ b/app/delivery/web/api/restricted/customer.go @@ -96,8 +96,8 @@ func (h *customerHandler) listCustomers(fc fiber.Ctx) error { } var columnMappingListUsers map[string]string = map[string]string{ - "user_id": "users.id", - "email": "users.email", - "first_name": "users.first_name", - "second_name": "users.second_name", + "user_id": "users.id", + "email": "users.email", + "first_name": "users.first_name", + "last_name": "users.last_name", } diff --git a/app/repos/customerRepo/customerRepo.go b/app/repos/customerRepo/customerRepo.go index 9f325c2..668785f 100644 --- a/app/repos/customerRepo/customerRepo.go +++ b/app/repos/customerRepo/customerRepo.go @@ -9,7 +9,11 @@ import ( type UICustomerRepo interface { Get(id uint) (*model.Customer, error) + GetByEmail(email string) (*model.Customer, error) + GetByExternalProviderId(provider model.AuthProvider, id string) (*model.Customer, error) Find(langId uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.UserInList], error) + Save(customer *model.Customer) error + Create(customer *model.Customer) error } type CustomerRepo struct{} @@ -29,6 +33,30 @@ func (repo *CustomerRepo) Get(id uint) (*model.Customer, error) { return &customer, err } +func (repo *CustomerRepo) GetByEmail(email string) (*model.Customer, error) { + var customer model.Customer + + err := db.DB. + Preload("Role.Permissions"). + Where("email = ?", email). + First(&customer). + Error + + return &customer, err +} + +func (repo *CustomerRepo) GetByExternalProviderId(provider model.AuthProvider, id string) (*model.Customer, error) { + var customer model.Customer + + err := db.DB. + Preload("Role.Permissions"). + Where("provider = ? AND provider_id = ?", provider, id). + First(&customer). + Error + + return &customer, err +} + func (repo *CustomerRepo) Find(langId uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.UserInList], error) { found, err := find.Paginate[model.UserInList](langId, p, db.DB. Table("b2b_customers AS users"). @@ -44,6 +72,59 @@ func (repo *CustomerRepo) Find(langId uint, p find.Paging, filt *filters.Filters return &found, err } +func (repo *CustomerRepo) Save(customer *model.Customer) error { + return db.DB.Save(customer).Error +} + +func (repo *CustomerRepo) Create(customer *model.Customer) error { + return db.DB.Create(customer).Error +} + +// func (repo *CustomerRepo) Search( +// customerId uint, +// partnerCode string, +// p find.Paging, +// filt *filters.FiltersList, +// search string, +// ) (found find.Found[model.UserInList], err error) { +// words := strings.Fields(search) +// if len(words) > 5 { +// words = words[:5] +// } + +// query := ctx.DB(). +// Model(&model.Customer{}). +// Select("customer.id AS id, customer.first_name as first_name, customer.last_name as last_name, customer.phone_number AS phone_number, customer.email AS email, count(distinct investment_plan_contract.id) as iiplan_purchases, count(distinct `order`.id) as single_purchases, entity.name as entity_name"). +// Where("customer.id <> ?", customerId). +// Where("(customer.id IN (SELECT id FROM customer WHERE partner_code IN (WITH RECURSIVE partners AS (SELECT code AS dst FROM partner WHERE code = ? UNION SELECT code FROM partner JOIN partners ON partners.dst = partner.superior_code) SELECT dst FROM partners)) OR customer.recommender_code = ?)", partnerCode, partnerCode). +// Scopes(view.CustomerListQuery()) + +// var conditions []string +// var args []interface{} +// for _, word := range words { + +// conditions = append(conditions, ` +// (LOWER(first_name) LIKE ? OR +// LOWER(last_name) LIKE ? OR +// phone_number LIKE ? OR +// LOWER(email) LIKE ?) +// `) + +// for i := 0; i < 4; i++ { +// args = append(args, "%"+strings.ToLower(word)+"%") +// } +// } + +// finalQuery := strings.Join(conditions, " AND ") + +// query = query.Where(finalQuery, args...). +// Scopes(filt.All()...) + +// found, err = find.Paginate[V](ctx, p, query) + +// return found, errs.Recorded(span, err) +// } + // func (repo *ListRepo) ListUsers(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.UserInList], error) { // var list []model.UserInList // var total int64 diff --git a/app/repos/rolesRepo/rolesRepo.go b/app/repos/rolesRepo/rolesRepo.go new file mode 100644 index 0000000..e87e10f --- /dev/null +++ b/app/repos/rolesRepo/rolesRepo.go @@ -0,0 +1,22 @@ +package roleRepo + +import ( + "git.ma-al.com/goc_daniel/b2b/app/db" + "git.ma-al.com/goc_daniel/b2b/app/model" +) + +type UIRolesRepo interface { + Get(id uint) (*model.Role, error) +} + +type RolesRepo struct{} + +func New() UIRolesRepo { + return &RolesRepo{} +} + +func (r *RolesRepo) Get(id uint) (*model.Role, error) { + var role model.Role + err := db.DB.First(&role, id).Error + return &role, err +} diff --git a/app/service/authService/auth.go b/app/service/authService/auth.go index ba1fa67..ebc9e32 100644 --- a/app/service/authService/auth.go +++ b/app/service/authService/auth.go @@ -11,6 +11,8 @@ import ( "git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/db" "git.ma-al.com/goc_daniel/b2b/app/model" + "git.ma-al.com/goc_daniel/b2b/app/repos/customerRepo" + roleRepo "git.ma-al.com/goc_daniel/b2b/app/repos/rolesRepo" "git.ma-al.com/goc_daniel/b2b/app/service/emailService" constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data" "git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors" @@ -35,17 +37,21 @@ type JWTClaims struct { // AuthService handles authentication operations type AuthService struct { - db *gorm.DB - config *config.AuthConfig - email *emailService.EmailService + db *gorm.DB + config *config.AuthConfig + email *emailService.EmailService + customerRepo customerRepo.UICustomerRepo + roleRepo roleRepo.UIRolesRepo } // NewAuthService creates a new AuthService instance func NewAuthService() *AuthService { svc := &AuthService{ - db: db.Get(), - config: &config.Get().Auth, - email: emailService.NewEmailService(), + db: db.Get(), + config: &config.Get().Auth, + email: emailService.NewEmailService(), + customerRepo: customerRepo.New(), + roleRepo: roleRepo.New(), } // Auto-migrate the refresh_tokens table if svc.db != nil { diff --git a/app/service/authService/google_oauth.go b/app/service/authService/google_oauth.go index d8c1820..d517c6d 100644 --- a/app/service/authService/google_oauth.go +++ b/app/service/authService/google_oauth.go @@ -108,26 +108,32 @@ 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 *view.GoogleUserInfo) (*model.Customer, error) { - var user model.Customer + var user *model.Customer // Try to find by provider + provider_id - err := s.db.Where("provider = ? AND provider_id = ?", model.ProviderGoogle, info.ID).First(&user).Error + user, err := s.customerRepo.GetByExternalProviderId(model.ProviderGoogle, info.ID) if err == nil { // Update avatar in case it changed user.AvatarURL = info.Picture - s.db.Save(&user) - return &user, nil + err = s.customerRepo.Save(user) + if err != nil { + return nil, err + } + return user, nil } // Try to find by email (user may have registered locally before) - err = s.db.Where("email = ?", info.Email).First(&user).Error + user, err = s.customerRepo.GetByEmail(info.Email) if err == nil { // Link Google provider to existing account user.Provider = model.ProviderGoogle user.ProviderID = info.ID user.AvatarURL = info.Picture user.IsActive = true - s.db.Save(&user) + err = s.customerRepo.Save(user) + if err != nil { + return nil, err + } // If email has not been verified yet, send email to admin. if !user.EmailVerified { @@ -139,7 +145,7 @@ func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model. } user.EmailVerified = true - return &user, nil + return user, nil } // Create new user @@ -148,6 +154,7 @@ func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model. FirstName: info.GivenName, LastName: info.FamilyName, Provider: model.ProviderGoogle, + RoleID: 1, // user ProviderID: info.ID, AvatarURL: info.Picture, IsActive: true, @@ -156,7 +163,7 @@ func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model. CountryID: 2, // default is England } - if err := s.db.Create(&newUser).Error; err != nil { + if err := s.customerRepo.Create(&newUser); err != nil { return nil, fmt.Errorf("failed to create user: %w", err) } @@ -169,6 +176,13 @@ func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model. } } + var role *model.Role + role, err = s.roleRepo.Get(newUser.RoleID) + if err != nil { + return nil, err + } + newUser.Role = role + return &newUser, nil }