package client import ( "github.com/google/uuid" "gorm.io/gorm" "netidhub-saas-be/app/database/entity" ) // GetAccessibleClientIDs returns all client IDs that a user has access to // This includes: // - User's primary client // - Clients granted via UserClientAccess // - Sub-clients if IncludeSubClients is true func GetAccessibleClientIDs(db *gorm.DB, userId uint, isSuperAdmin bool) ([]uuid.UUID, error) { if isSuperAdmin { // Super admin has access to ALL clients return nil, nil // nil means no filter (all clients) } var clientIDs []uuid.UUID // Get user's primary client var user entity.Users if err := db.Select("client_id").Where("id = ?", userId).First(&user).Error; err == nil { if user.ClientId != nil { clientIDs = append(clientIDs, *user.ClientId) } } // Get additional client accesses var accesses []entity.UserClientAccess err := db.Where("user_id = ? AND is_active = ?", userId, true). Preload("Client"). Find(&accesses).Error if err != nil { return clientIDs, err } for _, access := range accesses { clientIDs = append(clientIDs, access.ClientId) // If IncludeSubClients is true, get all sub-clients if access.IncludeSubClients != nil && *access.IncludeSubClients { subClientIDs, err := GetSubClientIDs(db, access.ClientId) if err == nil { clientIDs = append(clientIDs, subClientIDs...) } } } return removeDuplicateUUIDs(clientIDs), nil } // GetSubClientIDs returns all sub-client IDs for a given parent client (recursive) func GetSubClientIDs(db *gorm.DB, parentClientId uuid.UUID) ([]uuid.UUID, error) { var clientIDs []uuid.UUID var subClients []entity.Clients // Get direct children err := db.Where("parent_client_id = ? AND is_active = ?", parentClientId, true). Find(&subClients).Error if err != nil { return nil, err } for _, subClient := range subClients { clientIDs = append(clientIDs, subClient.ID) // Recursively get sub-clients of sub-clients nestedSubClientIDs, err := GetSubClientIDs(db, subClient.ID) if err == nil { clientIDs = append(clientIDs, nestedSubClientIDs...) } } return clientIDs, nil } // GetClientHierarchy returns the full client hierarchy (parent chain and children) func GetClientHierarchy(db *gorm.DB, clientId uuid.UUID) (*entity.Clients, error) { var client entity.Clients err := db.Preload("ParentClient"). Preload("SubClients", "is_active = ?", true). Where("id = ?", clientId). First(&client).Error return &client, err } // HasAccessToClient checks if a user has access to a specific client func HasAccessToClient(db *gorm.DB, userId uint, clientId uuid.UUID, isSuperAdmin bool) (bool, error) { if isSuperAdmin { return true, nil } accessibleClientIDs, err := GetAccessibleClientIDs(db, userId, isSuperAdmin) if err != nil { return false, err } // nil means all clients (super admin case) if accessibleClientIDs == nil { return true, nil } for _, id := range accessibleClientIDs { if id == clientId { return true, nil } } return false, nil } // GetParentClientID returns the root/parent client ID for a given client func GetParentClientID(db *gorm.DB, clientId uuid.UUID) (*uuid.UUID, error) { var client entity.Clients err := db.Preload("ParentClient").Where("id = ?", clientId).First(&client).Error if err != nil { return nil, err } // If has parent, recursively get the root parent if client.ParentClientId != nil { return GetParentClientID(db, *client.ParentClientId) } // This is the root parent return &client.ID, nil } // IsParentClient checks if a client is a parent client (has sub-clients) func IsParentClient(db *gorm.DB, clientId uuid.UUID) (bool, error) { var count int64 err := db.Model(&entity.Clients{}). Where("parent_client_id = ? AND is_active = ?", clientId, true). Count(&count).Error return count > 0, err } // removeDuplicateUUIDs removes duplicate UUIDs from a slice func removeDuplicateUUIDs(uuids []uuid.UUID) []uuid.UUID { encountered := map[uuid.UUID]bool{} result := []uuid.UUID{} for _, uuid := range uuids { if !encountered[uuid] { encountered[uuid] = true result = append(result, uuid) } } return result }