1
0
forked from baron/baron-sso

feat: allow regular users to view their own tenant's org chart

Changes the /users endpoint to allow RoleUser access and securely restricts the returned data to only users within their affiliated tenants. Removes the unnecessary back button from the Org Chart view since it's now a top-level nav item.
This commit is contained in:
2026-04-13 10:47:56 +09:00
parent 984adcfa62
commit d3a82d1653
4 changed files with 39 additions and 24 deletions

View File

@@ -100,13 +100,17 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error {
// [New] Manageable Tenants Map for efficient lookup
manageableSlugs := make(map[string]bool)
if requesterRole == domain.RoleTenantAdmin {
if requesterRole == domain.RoleTenantAdmin || requesterRole == domain.RoleUser || requesterRole == domain.RoleRPAdmin {
profile, _ := c.Locals("user_profile").(*domain.UserProfileResponse)
if profile != nil {
for _, t := range profile.ManageableTenants {
manageableSlugs[strings.ToLower(t.Slug)] = true
manageableSlugs[strings.ToLower(t.ID)] = true // Add ID as well
}
for _, t := range profile.JoinedTenants {
manageableSlugs[strings.ToLower(t.Slug)] = true
manageableSlugs[strings.ToLower(t.ID)] = true
}
// Include primary tenant slug if not already there
if profile.CompanyCode != "" {
manageableSlugs[strings.ToLower(profile.CompanyCode)] = true
@@ -137,8 +141,8 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error {
compCode := strings.ToLower(extractTraitString(identity.Traits, "companyCode"))
tID := strings.ToLower(extractTraitString(identity.Traits, "tenant_id"))
// Tenant Admin filtering
if requesterRole == domain.RoleTenantAdmin {
// Tenant Admin & Member filtering
if requesterRole == domain.RoleTenantAdmin || requesterRole == domain.RoleUser || requesterRole == domain.RoleRPAdmin {
if !manageableSlugs[compCode] && !manageableSlugs[tID] {
continue
}
@@ -194,6 +198,15 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error {
// 2. Fallback to Local DB if Kratos is down
slog.Warn("Kratos unavailable, falling back to local DB for user list", "error", err)
// If requester is not Super Admin, we should technically filter by manageable slugs in DB too.
// For simplicity in fallback, if tenantSlug is empty we default to their primary company code.
if (requesterRole == domain.RoleTenantAdmin || requesterRole == domain.RoleUser || requesterRole == domain.RoleRPAdmin) && tenantSlug == "" {
profile, _ := c.Locals("user_profile").(*domain.UserProfileResponse)
if profile != nil && profile.CompanyCode != "" {
tenantSlug = profile.CompanyCode
}
}
// Fetch from UserRepo
users, total, err := h.UserRepo.List(c.Context(), offset, limit, search, tenantSlug)
if err != nil {