forked from baron/baron-sso
feat: implement bulk user group/tenant move functionality
This commit is contained in:
@@ -673,9 +673,11 @@ func (h *UserHandler) ExportUsersCSV(c *fiber.Ctx) error {
|
||||
|
||||
func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
|
||||
var req struct {
|
||||
UserIDs []string `json:"userIds"`
|
||||
Status *string `json:"status"`
|
||||
Role *string `json:"role"`
|
||||
UserIDs []string `json:"userIds"`
|
||||
Status *string `json:"status"`
|
||||
Role *string `json:"role"`
|
||||
CompanyCode *string `json:"companyCode"`
|
||||
Department *string `json:"department"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errorJSON(c, fiber.StatusBadRequest, "invalid request body")
|
||||
@@ -690,7 +692,13 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized")
|
||||
}
|
||||
|
||||
// Build manageable slugs map if tenant_admin
|
||||
// [New] Pre-fetch tenant cache if companyCode is being changed
|
||||
type tenantCacheItem struct {
|
||||
ID string
|
||||
Schema []interface{}
|
||||
}
|
||||
tenantCache := make(map[string]tenantCacheItem)
|
||||
|
||||
manageableSlugs := make(map[string]bool)
|
||||
if requester.Role == domain.RoleTenantAdmin {
|
||||
for _, t := range requester.ManageableTenants {
|
||||
@@ -711,12 +719,19 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// Authorization check
|
||||
userComp := strings.ToLower(extractTraitString(identity.Traits, "companyCode"))
|
||||
if requester.Role == domain.RoleTenantAdmin {
|
||||
userComp := strings.ToLower(extractTraitString(identity.Traits, "companyCode"))
|
||||
if !manageableSlugs[userComp] {
|
||||
results = append(results, map[string]any{"id": id, "success": false, "message": "forbidden: user belongs to another tenant"})
|
||||
continue
|
||||
}
|
||||
// If changing companyCode, must be to a manageable one
|
||||
if req.CompanyCode != nil {
|
||||
if !manageableSlugs[strings.ToLower(*req.CompanyCode)] {
|
||||
results = append(results, map[string]any{"id": id, "success": false, "message": "forbidden: target tenant not manageable"})
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare updates
|
||||
@@ -724,6 +739,24 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
|
||||
if req.Role != nil {
|
||||
traits["role"] = *req.Role
|
||||
}
|
||||
if req.CompanyCode != nil {
|
||||
traits["companyCode"] = *req.CompanyCode
|
||||
|
||||
// Resolve and update tenant_id in traits if changed
|
||||
if tItem, exists := tenantCache[*req.CompanyCode]; exists {
|
||||
traits["tenant_id"] = tItem.ID
|
||||
} else if h.TenantService != nil {
|
||||
tenant, err := h.TenantService.GetTenantBySlug(c.Context(), *req.CompanyCode)
|
||||
if err == nil && tenant != nil {
|
||||
tItem.ID = tenant.ID
|
||||
tenantCache[*req.CompanyCode] = tItem
|
||||
traits["tenant_id"] = tenant.ID
|
||||
}
|
||||
}
|
||||
}
|
||||
if req.Department != nil {
|
||||
traits["department"] = *req.Department
|
||||
}
|
||||
|
||||
state := identity.State
|
||||
if req.Status != nil {
|
||||
@@ -743,12 +776,10 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
|
||||
// Sync to local DB
|
||||
if h.UserRepo != nil {
|
||||
localUser := h.mapToLocalUser(*identity)
|
||||
if req.Role != nil {
|
||||
localUser.Role = *req.Role
|
||||
}
|
||||
if req.Status != nil {
|
||||
localUser.Status = *req.Status
|
||||
}
|
||||
if req.Role != nil { localUser.Role = *req.Role }
|
||||
if req.Status != nil { localUser.Status = *req.Status }
|
||||
if req.CompanyCode != nil { localUser.CompanyCode = *req.CompanyCode }
|
||||
if req.Department != nil { localUser.Department = *req.Department }
|
||||
_ = h.UserRepo.Update(c.Context(), localUser)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user