package service import ( "fmt" "netidhub-saas-be/app/database/entity" "netidhub-saas-be/app/module/client_approval_settings/mapper" "netidhub-saas-be/app/module/client_approval_settings/repository" "netidhub-saas-be/app/module/client_approval_settings/request" "netidhub-saas-be/app/module/client_approval_settings/response" usersRepository "netidhub-saas-be/app/module/users/repository" utilSvc "netidhub-saas-be/utils/service" "github.com/google/uuid" "github.com/rs/zerolog" ) type clientApprovalSettingsService struct { clientApprovalSettingsRepo repository.ClientApprovalSettingsRepository UsersRepo usersRepository.UsersRepository Log zerolog.Logger } type ClientApprovalSettingsService interface { GetByClientId(authToken string) (*response.ClientApprovalSettingsResponse, error) Create(authToken string, req request.CreateClientApprovalSettingsRequest) (*response.ClientApprovalSettingsResponse, error) Update(authToken string, req request.UpdateClientApprovalSettingsRequest) (*response.ClientApprovalSettingsResponse, error) Delete(authToken string) error ToggleApprovalRequirement(authToken string, requiresApproval bool) error SetDefaultWorkflow(authToken string, workflowId *uint) error AddExemptUser(authToken string, userId uint) error RemoveExemptUser(authToken string, userId uint) error AddExemptRole(authToken string, roleId uint) error RemoveExemptRole(authToken string, roleId uint) error AddExemptCategory(authToken string, categoryId uint) error RemoveExemptCategory(authToken string, categoryId uint) error CheckIfApprovalRequired(authToken string, userId uint, userLevelId uint, categoryId uint, contentType string) (bool, error) // Enhanced methods for dynamic approval management EnableApprovalWithTransition(authToken string, defaultWorkflowId *uint) error DisableApprovalWithAutoPublish(authToken string, reason string) error HandlePendingApprovalsOnDisable(authToken string, action string) error // "auto_approve", "keep_pending", "reset_to_draft" } func NewClientApprovalSettingsService( clientApprovalSettingsRepo repository.ClientApprovalSettingsRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger, ) ClientApprovalSettingsService { return &clientApprovalSettingsService{ clientApprovalSettingsRepo: clientApprovalSettingsRepo, UsersRepo: usersRepo, Log: log, } } func (_i *clientApprovalSettingsService) GetByClientId(authToken string) (*response.ClientApprovalSettingsResponse, error) { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return nil, fmt.Errorf("clientId not found in auth token") } settings, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return nil, err } if settings == nil { // Return default settings if none found return &response.ClientApprovalSettingsResponse{ ClientId: clientId.String(), RequiresApproval: true, // Default to requiring approval AutoPublishArticles: false, ApprovalExemptUsers: []uint{}, ApprovalExemptRoles: []uint{}, ApprovalExemptCategories: []uint{}, RequireApprovalFor: []string{}, SkipApprovalFor: []string{}, IsActive: true, }, nil } return mapper.ClientApprovalSettingsResponseMapper(_i.Log, clientId, settings), nil } func (_i *clientApprovalSettingsService) Create(authToken string, req request.CreateClientApprovalSettingsRequest) (*response.ClientApprovalSettingsResponse, error) { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return nil, fmt.Errorf("clientId not found in auth token") } // Check if settings already exist existing, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return nil, err } if existing != nil { return nil, fmt.Errorf("approval settings already exist for this client") } // Create new settings settings := &entity.ClientApprovalSettings{ RequiresApproval: &req.RequiresApproval, DefaultWorkflowId: req.DefaultWorkflowId, AutoPublishArticles: &req.AutoPublishArticles, ApprovalExemptUsers: req.ApprovalExemptUsers, ApprovalExemptRoles: req.ApprovalExemptRoles, ApprovalExemptCategories: req.ApprovalExemptCategories, RequireApprovalFor: req.RequireApprovalFor, SkipApprovalFor: req.SkipApprovalFor, IsActive: &req.IsActive, } createdSettings, err := _i.clientApprovalSettingsRepo.Create(clientId, settings) if err != nil { return nil, err } return mapper.ClientApprovalSettingsResponseMapper(_i.Log, clientId, createdSettings), nil } func (_i *clientApprovalSettingsService) Update(authToken string, req request.UpdateClientApprovalSettingsRequest) (*response.ClientApprovalSettingsResponse, error) { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return nil, fmt.Errorf("clientId not found in auth token") } // Get existing settings settings, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return nil, err } if settings == nil { return nil, fmt.Errorf("approval settings not found for this client") } // Update fields if provided if req.RequiresApproval != nil { settings.RequiresApproval = req.RequiresApproval } if req.DefaultWorkflowId != nil { settings.DefaultWorkflowId = *req.DefaultWorkflowId } if req.AutoPublishArticles != nil { settings.AutoPublishArticles = req.AutoPublishArticles } if req.ApprovalExemptUsers != nil { settings.ApprovalExemptUsers = req.ApprovalExemptUsers } if req.ApprovalExemptRoles != nil { settings.ApprovalExemptRoles = req.ApprovalExemptRoles } if req.ApprovalExemptCategories != nil { settings.ApprovalExemptCategories = req.ApprovalExemptCategories } if req.RequireApprovalFor != nil { settings.RequireApprovalFor = req.RequireApprovalFor } if req.SkipApprovalFor != nil { settings.SkipApprovalFor = req.SkipApprovalFor } if req.IsActive != nil { settings.IsActive = req.IsActive } updatedSettings, err := _i.clientApprovalSettingsRepo.Update(clientId, settings) if err != nil { return nil, err } return mapper.ClientApprovalSettingsResponseMapper(_i.Log, clientId, updatedSettings), nil } func (_i *clientApprovalSettingsService) Delete(authToken string) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.Delete(clientId) } func (_i *clientApprovalSettingsService) ToggleApprovalRequirement(authToken string, requiresApproval bool) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } settings, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return err } if settings == nil { return fmt.Errorf("approval settings not found for this client") } settings.RequiresApproval = &requiresApproval _, err = _i.clientApprovalSettingsRepo.Update(clientId, settings) return err } func (_i *clientApprovalSettingsService) SetDefaultWorkflow(authToken string, workflowId *uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } settings, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return err } if settings == nil { return fmt.Errorf("approval settings not found for this client") } settings.DefaultWorkflowId = workflowId _, err = _i.clientApprovalSettingsRepo.Update(clientId, settings) return err } func (_i *clientApprovalSettingsService) AddExemptUser(authToken string, userId uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.AddExemptUser(clientId, userId) } func (_i *clientApprovalSettingsService) RemoveExemptUser(authToken string, userId uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.RemoveExemptUser(clientId, userId) } func (_i *clientApprovalSettingsService) AddExemptRole(authToken string, roleId uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.AddExemptRole(clientId, roleId) } func (_i *clientApprovalSettingsService) RemoveExemptRole(authToken string, roleId uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.RemoveExemptRole(clientId, roleId) } func (_i *clientApprovalSettingsService) AddExemptCategory(authToken string, categoryId uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.AddExemptCategory(clientId, categoryId) } func (_i *clientApprovalSettingsService) RemoveExemptCategory(authToken string, categoryId uint) error { // Extract clientId from authToken var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } return _i.clientApprovalSettingsRepo.RemoveExemptCategory(clientId, categoryId) } func (_i *clientApprovalSettingsService) CheckIfApprovalRequired(authToken string, userId uint, userLevelId uint, categoryId uint, contentType string) (bool, error) { var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return true, fmt.Errorf("clientId not found in auth token") } settings, err := _i.clientApprovalSettingsRepo.FindActiveSettings(clientId) if err != nil { return true, err // Default to requiring approval on error } if settings == nil { return true, nil // Default to requiring approval if no settings } // Check if approval is disabled if settings.RequiresApproval != nil && !*settings.RequiresApproval { return false, nil } // Check user exemption for _, exemptUserId := range settings.ApprovalExemptUsers { if exemptUserId == userId { return false, nil } } // Check role exemption for _, exemptRoleId := range settings.ApprovalExemptRoles { if exemptRoleId == userLevelId { return false, nil } } // Check category exemption for _, exemptCategoryId := range settings.ApprovalExemptCategories { if exemptCategoryId == categoryId { return false, nil } } // Check content type exemptions for _, skipType := range settings.SkipApprovalFor { if skipType == contentType { return false, nil } } // Check if content type requires approval for _, requireType := range settings.RequireApprovalFor { if requireType == contentType { return true, nil } } // Default to requiring approval return true, nil } func (_i *clientApprovalSettingsService) EnableApprovalWithTransition(authToken string, defaultWorkflowId *uint) error { var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } settings, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return err } if settings == nil { // Create new settings settings = &entity.ClientApprovalSettings{ RequiresApproval: &[]bool{true}[0], DefaultWorkflowId: defaultWorkflowId, AutoPublishArticles: &[]bool{false}[0], IsActive: &[]bool{true}[0], } _, err = _i.clientApprovalSettingsRepo.Create(clientId, settings) } else { // Update existing settings settings.RequiresApproval = &[]bool{true}[0] settings.DefaultWorkflowId = defaultWorkflowId settings.AutoPublishArticles = &[]bool{false}[0] settings.IsActive = &[]bool{true}[0] _, err = _i.clientApprovalSettingsRepo.Update(clientId, settings) } return err } func (_i *clientApprovalSettingsService) DisableApprovalWithAutoPublish(authToken string, reason string) error { var clientId *uuid.UUID if authToken != "" { user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user != nil && user.ClientId != nil { clientId = user.ClientId _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") } } if clientId == nil { return fmt.Errorf("clientId not found in auth token") } settings, err := _i.clientApprovalSettingsRepo.FindByClientId(*clientId) if err != nil { return err } if settings == nil { return fmt.Errorf("approval settings not found for this client") } settings.RequiresApproval = &[]bool{false}[0] settings.AutoPublishArticles = &[]bool{true}[0] settings.IsActive = &[]bool{true}[0] _, err = _i.clientApprovalSettingsRepo.Update(clientId, settings) return err } func (_i *clientApprovalSettingsService) HandlePendingApprovalsOnDisable(authToken string, action string) error { // This would typically interact with article approval flows // For now, just log the action _i.Log.Info(). Str("client_id", authToken). Str("action", action). Msg("Handling pending approvals on disable") // TODO: Implement actual logic based on action: // - "auto_approve": Auto approve all pending articles // - "keep_pending": Keep articles in pending state // - "reset_to_draft": Reset articles to draft state return nil }