kontenhumas-be/utils/client/client_hierarchy.go

160 lines
4.1 KiB
Go

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
}