From ea44785ef0c6e1ad85978d867cc1bf28c45f3695 Mon Sep 17 00:00:00 2001 From: chan Date: Mon, 13 Apr 2026 10:51:29 +0900 Subject: [PATCH] feat: expand manageableSlugs to include entire tenant tree for users Allows users and tenant admins to view users across all tenants within their hierarchy (both parent and child organizations) instead of just their direct tenant. --- backend/internal/handler/user_handler.go | 46 +++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/backend/internal/handler/user_handler.go b/backend/internal/handler/user_handler.go index 147e85e5..ea522069 100644 --- a/backend/internal/handler/user_handler.go +++ b/backend/internal/handler/user_handler.go @@ -103,13 +103,16 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error { if requesterRole == domain.RoleTenantAdmin || requesterRole == domain.RoleUser || requesterRole == domain.RoleRPAdmin { profile, _ := c.Locals("user_profile").(*domain.UserProfileResponse) if profile != nil { + var baseTenantIDs []string for _, t := range profile.ManageableTenants { manageableSlugs[strings.ToLower(t.Slug)] = true - manageableSlugs[strings.ToLower(t.ID)] = true // Add ID as well + manageableSlugs[strings.ToLower(t.ID)] = true + baseTenantIDs = append(baseTenantIDs, t.ID) } for _, t := range profile.JoinedTenants { manageableSlugs[strings.ToLower(t.Slug)] = true manageableSlugs[strings.ToLower(t.ID)] = true + baseTenantIDs = append(baseTenantIDs, t.ID) } // Include primary tenant slug if not already there if profile.CompanyCode != "" { @@ -117,6 +120,47 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error { } if profile.TenantID != nil { manageableSlugs[strings.ToLower(*profile.TenantID)] = true + baseTenantIDs = append(baseTenantIDs, *profile.TenantID) + } + + // Expand manageableSlugs to the entire tenant tree (root + all descendants) + if h.TenantService != nil && len(baseTenantIDs) > 0 { + allTenants, _, err := h.TenantService.ListTenants(c.Context(), 10000, 0, "") + if err == nil { + parentMap := make(map[string]string) + for _, t := range allTenants { + if t.ParentID != nil { + parentMap[t.ID] = *t.ParentID + } + } + + // Function to find the root of any given tenant + findRoot := func(id string) string { + curr := id + for { + p, exists := parentMap[curr] + if !exists || p == "" { + break + } + curr = p + } + return curr + } + + // Collect root IDs for all base tenants + roots := make(map[string]bool) + for _, id := range baseTenantIDs { + roots[findRoot(id)] = true + } + + // If a tenant shares a root with any base tenant, it's in the same tree family + for _, t := range allTenants { + if roots[findRoot(t.ID)] { + manageableSlugs[strings.ToLower(t.Slug)] = true + manageableSlugs[strings.ToLower(t.ID)] = true + } + } + } } } }