fix(core): use multi-call strategy for inclusive User Management scope

- Updated load_ae_obj_li__user to handle 'All' scope by fetching account and global users separately.
- Ensured Search API uses authorized account_id_random field with op: 'eq' for null.
- Fixed 404 for global lookups by avoiding [NULL] in standard List API.
This commit is contained in:
Scott Idem
2026-01-15 16:17:25 -05:00
parent c219c78e8f
commit 52f5d0bab6

View File

@@ -92,68 +92,27 @@ export async function load_ae_obj_li__user({
try_cache?: boolean;
log_lvl?: number;
}): Promise<ae_User[]> {
let promise;
if (log_lvl) {
console.log(`*** load_ae_obj_li__user() *** for_obj_id=${for_obj_id} include_global=${include_global} qry_str=${qry_str}`);
}
// We use Search if there is a query string, OR if we need inclusive global logic
const use_search = qry_str || (for_obj_id && include_global) || (!for_obj_id && include_global);
if (use_search) {
const search_query: any = { and: [] };
if (qry_str) {
search_query.q = qry_str;
}
// Handle Account Scoping in Search Query
// SCENARIO A: Text Search
if (qry_str) {
const search_query: any = { q: qry_str, and: [] };
if (for_obj_id && include_global) {
// Case: (Account == current OR Account == null)
search_query.and.push({
or: [
{
field: `account_id_random`,
op: 'eq',
value: for_obj_id
},
{
field: `account_id_random`,
op: 'eq', // Use 'eq' with null, as 'is' was unsupported
value: null
}
{ field: `account_id_random`, op: 'eq', value: for_obj_id },
{ field: `account_id_random`, op: 'eq', value: null }
]
});
} else if (for_obj_id) {
// Case: Account Only (with qry_str)
search_query.and.push({
field: `account_id_random`,
op: 'eq',
value: for_obj_id
});
search_query.and.push({ field: `account_id_random`, op: 'eq', value: for_obj_id });
} else if (include_global) {
// Case: Global Only (No Account)
search_query.and.push({
field: `account_id_random`,
op: 'eq', // Use 'eq' with null
value: null
});
search_query.and.push({ field: `account_id_random`, op: 'eq', value: null });
}
if (enabled === 'enabled') {
search_query.and.push({ field: 'enable', op: 'eq', value: true });
} else if (enabled === 'not_enabled') {
search_query.and.push({ field: 'enable', op: 'eq', value: false });
}
if (hidden === 'hidden') {
search_query.and.push({ field: 'hide', op: 'eq', value: true });
} else if (hidden === 'not_hidden') {
search_query.and.push({ field: 'hide', op: 'eq', value: false });
}
if (log_lvl) {
console.log(`load_ae_obj_li__user() - Using Search API`, JSON.stringify(search_query, null, 2));
}
promise = api.search_ae_obj_v3({
return await api.search_ae_obj_v3({
api_cfg,
obj_type: 'user',
search_query,
@@ -165,49 +124,58 @@ export async function load_ae_obj_li__user({
offset,
log_lvl
});
} else {
// Simple case: Standard List API (Account Only or No Filter)
if (log_lvl) {
console.log(`load_ae_obj_li__user() - Using List API (for_obj_id=${for_obj_id})`);
}
}
// SCENARIO B: Multi-Scope (Account + Global) with no search string
if (for_obj_id && include_global) {
if (log_lvl) console.log('Strategy: Multi-call (Account + Global)');
const [acct_users, global_users] = await Promise.all([
load_ae_obj_li__user({ api_cfg, for_obj_id, include_global: false, enabled, hidden, view, limit, log_lvl }),
load_ae_obj_li__user({ api_cfg, for_obj_id: null, include_global: true, enabled, hidden, view, limit, log_lvl })
]);
promise = api.get_ae_obj_li_v3({
// Merge and unique-ify by ID
const merged = [...acct_users, ...global_users];
const unique = Array.from(new Map(merged.map(u => [u.user_id_random, u])).values());
return unique;
}
// SCENARIO C: Global Only (no search string)
if (!for_obj_id && include_global) {
if (log_lvl) console.log('Strategy: Search API for Global Only');
// Since for_obj_id is NULL in List API is tricky, use Search with a direct filter
const search_query = {
and: [{ field: 'account_id_random', op: 'eq', value: null }]
};
return await api.search_ae_obj_v3({
api_cfg,
obj_type: 'user',
for_obj_type: for_obj_id ? for_obj_type : undefined,
for_obj_id: for_obj_id || undefined,
search_query,
enabled,
hidden,
view,
order_by_li,
limit,
offset,
order_by_li,
log_lvl
});
}
ae_promises.load__user_obj_li = await promise.then(async function (result_li) {
if (result_li) {
if (try_cache) {
const processed_obj_li = await process_ae_obj__user_props({
obj_li: result_li,
log_lvl
});
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'user',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl
});
}
return result_li;
} else {
return [];
}
// SCENARIO D: Account Only or Everything (confirmed working List API)
if (log_lvl) console.log(`Strategy: Standard List API (for_obj_id=${for_obj_id})`);
return await api.get_ae_obj_li_v3({
api_cfg,
obj_type: 'user',
for_obj_type: for_obj_id ? for_obj_type : undefined,
for_obj_id: for_obj_id || undefined,
enabled,
hidden,
view,
limit,
offset,
order_by_li,
log_lvl
});
return ae_promises.load__user_obj_li;
}
// Updated 2026-01-06
@@ -733,4 +701,4 @@ export async function process_ae_obj__user_props({
obj_type: 'user',
log_lvl
});
}
}