Fix: Harden V3 search logic and restore specialized business mapping
- API: Updated `search_ae_obj_v3` to correctly serialize complex URL parameters (JSON). - Events: Restored "sacred" business logic for Event Badge and Session searches using `ft_qry` and `lk_qry`. - PWA: Fixed manifest path in `app.html` to resolve 404 errors. - Documentation: Updated `GEMINI.md` and `TODO.md` with recent search hardening accomplishments.
This commit is contained in:
@@ -14,6 +14,7 @@ interface SearchAeObjV3Params {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
delay_ms?: number;
|
||||
params?: key_val;
|
||||
headers?: any;
|
||||
log_lvl?: number;
|
||||
}
|
||||
@@ -31,29 +32,38 @@ export async function search_ae_obj_v3({
|
||||
limit = 100,
|
||||
offset = 0,
|
||||
delay_ms = 0,
|
||||
params = {},
|
||||
headers = {},
|
||||
log_lvl = 0
|
||||
}: SearchAeObjV3Params) {
|
||||
const endpoint = `/v3/crud/${obj_type}/search`;
|
||||
|
||||
// Hybrid search: Standard filters passed as query params
|
||||
const params: key_val = {
|
||||
const query_params: key_val = {
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset
|
||||
offset,
|
||||
...params
|
||||
};
|
||||
|
||||
if (for_obj_type) params['for_obj_type'] = for_obj_type;
|
||||
if (for_obj_id) params['for_obj_id'] = for_obj_id;
|
||||
if (order_by_li) params['order_by_li'] = JSON.stringify(order_by_li);
|
||||
if (delay_ms > 0) params['delay_ms'] = delay_ms;
|
||||
if (for_obj_type) query_params['for_obj_type'] = for_obj_type;
|
||||
if (for_obj_id) query_params['for_obj_id'] = for_obj_id;
|
||||
if (order_by_li) query_params['order_by_li'] = JSON.stringify(order_by_li);
|
||||
if (delay_ms > 0) query_params['delay_ms'] = delay_ms;
|
||||
|
||||
// Serialize any complex objects in the query params (e.g. ft_qry, lk_qry)
|
||||
for (const key in query_params) {
|
||||
if (typeof query_params[key] === 'object' && query_params[key] !== null) {
|
||||
query_params[key] = JSON.stringify(query_params[key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('*** search_ae_obj_v3 ***');
|
||||
console.log('Endpoint:', endpoint);
|
||||
console.log('Params:', params);
|
||||
console.log('Params:', query_params);
|
||||
console.log('Search Query:', search_query);
|
||||
}
|
||||
|
||||
@@ -61,7 +71,7 @@ export async function search_ae_obj_v3({
|
||||
return await post_object({
|
||||
api_cfg,
|
||||
endpoint,
|
||||
params,
|
||||
params: query_params,
|
||||
headers,
|
||||
data: search_query,
|
||||
log_lvl
|
||||
|
||||
@@ -328,84 +328,7 @@ export async function update_ae_obj__event_badge({
|
||||
return result;
|
||||
}
|
||||
|
||||
// Is this needed?
|
||||
// Updated 2026-01-02
|
||||
export async function qry__event_badge({
|
||||
api_cfg,
|
||||
event_id,
|
||||
qry_str = null,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
view = 'default',
|
||||
limit = 99,
|
||||
offset = 0,
|
||||
order_by_li = { priority: 'DESC', sort: 'DESC', updated_on: 'DESC', created_on: 'DESC' },
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
qry_str?: null | string;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: key_val;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** qry__event_badge() *** event_id=${event_id} qry_str=${qry_str}`);
|
||||
}
|
||||
|
||||
const search_query: any = { and: [] };
|
||||
if (qry_str) {
|
||||
search_query.q = qry_str;
|
||||
}
|
||||
|
||||
ae_promises.qry__event_badge_obj_li = await api
|
||||
.search_ae_obj_v3({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge',
|
||||
search_query,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
order_by_li,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
})
|
||||
.then(async function (badge_obj_li_get_result) {
|
||||
if (badge_obj_li_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
||||
obj_li: badge_obj_li_get_result,
|
||||
event_id,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return badge_obj_li_get_result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
return ae_promises.qry__event_badge_obj_li;
|
||||
}
|
||||
|
||||
// Updated 2026-01-02
|
||||
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
||||
export async function search__event_badge({
|
||||
api_cfg,
|
||||
event_id,
|
||||
@@ -421,15 +344,11 @@ export async function search__event_badge({
|
||||
limit = 25,
|
||||
offset = 0,
|
||||
order_by_li = {
|
||||
// print_count: 'ASC',
|
||||
// priority: 'DESC',
|
||||
// sort: 'DESC',
|
||||
given_name: 'ASC',
|
||||
family_name: 'ASC',
|
||||
updated_on: 'DESC',
|
||||
created_on: 'DESC'
|
||||
},
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
@@ -447,76 +366,62 @@ export async function search__event_badge({
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: key_val;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge[] | false> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__event_badge() *** event_id=${event_id} printed_status=${printed_status} affiliations=${affiliations_qry_str} order_by_li=`, order_by_li);
|
||||
console.log(`*** search__event_badge() *** event_id=${event_id} ft=${fulltext_search_qry_str}`);
|
||||
}
|
||||
|
||||
if (!fulltext_search_qry_str && !like_search_qry_str && !affiliations_qry_str && !type_code && !external_event_id && printed_status === 'all') {
|
||||
console.log('No search criteria provided!!!');
|
||||
return false;
|
||||
const search_query: any = {
|
||||
q: '',
|
||||
and: [{ field: 'event_id_random', op: 'eq', value: event_id }]
|
||||
};
|
||||
|
||||
const params: key_val = {};
|
||||
|
||||
// Restore Fulltext Logic (Aether Business Logic)
|
||||
if (fulltext_search_qry_str || affiliations_qry_str) {
|
||||
params['ft_qry'] = {};
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
|
||||
params['ft_qry']['default_qry_str'] = fulltext_search_qry_str;
|
||||
}
|
||||
if (affiliations_qry_str && affiliations_qry_str.length > 2) {
|
||||
params['ft_qry']['affiliations'] = affiliations_qry_str;
|
||||
}
|
||||
}
|
||||
|
||||
const search_query: any = {};
|
||||
const and_filters: any[] = [];
|
||||
|
||||
// Set Global Search
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
|
||||
search_query.q = fulltext_search_qry_str;
|
||||
}
|
||||
|
||||
// Add specific filters
|
||||
if (like_search_qry_str && like_search_qry_str.length > 2) {
|
||||
and_filters.push({
|
||||
field: 'default_qry_str',
|
||||
op: 'like',
|
||||
value: `%${like_search_qry_str.trim()}%`
|
||||
});
|
||||
}
|
||||
|
||||
if (affiliations_qry_str && affiliations_qry_str.length > 2) {
|
||||
and_filters.push({
|
||||
field: 'affiliations',
|
||||
op: 'like',
|
||||
value: `%${affiliations_qry_str.trim()}%`
|
||||
});
|
||||
// Restore Like Logic
|
||||
if (like_search_qry_str) {
|
||||
params['lk_qry'] = { 'default_qry_str': like_search_qry_str };
|
||||
}
|
||||
|
||||
if (external_event_id) {
|
||||
and_filters.push({ field: 'external_event_id', op: 'eq', value: external_event_id });
|
||||
search_query.and.push({ field: 'external_event_id', op: 'eq', value: external_event_id });
|
||||
}
|
||||
|
||||
if (type_code) {
|
||||
and_filters.push({ field: 'badge_type_code', op: 'eq', value: type_code });
|
||||
search_query.and.push({ field: 'badge_type_code', op: 'eq', value: type_code });
|
||||
}
|
||||
|
||||
if (printed_status === 'printed') {
|
||||
and_filters.push({ field: 'print_count', op: 'gt', value: 0 });
|
||||
search_query.and.push({ field: 'print_count', op: 'gt', value: 0 });
|
||||
} else if (printed_status === 'not_printed') {
|
||||
and_filters.push({ field: 'print_count', op: 'eq', value: 0 });
|
||||
search_query.and.push({ field: 'print_count', op: 'eq', value: 0 });
|
||||
}
|
||||
|
||||
if (and_filters.length > 0) {
|
||||
search_query.and = and_filters;
|
||||
}
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('Final search_query object:', JSON.stringify(search_query, null, 2));
|
||||
}
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
|
||||
ae_promises.search__event_badge_obj_li = await api
|
||||
.search_ae_obj_v3({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge',
|
||||
search_query,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
params, // Correctly pass the specialized business logic params
|
||||
order_by_li,
|
||||
limit,
|
||||
offset,
|
||||
@@ -542,9 +447,6 @@ export async function search__event_badge({
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
return ae_promises.search__event_badge_obj_li;
|
||||
}
|
||||
@@ -553,14 +455,8 @@ export async function search__event_badge({
|
||||
export const properties_to_save = [
|
||||
'id',
|
||||
'event_badge_id',
|
||||
// 'event_badge_id_random',
|
||||
|
||||
'event_id',
|
||||
// 'event_id_random',
|
||||
|
||||
'event_badge_template_id',
|
||||
// 'event_badge_template_id_random',
|
||||
|
||||
'pronouns',
|
||||
'informal_name',
|
||||
'title_names',
|
||||
@@ -568,19 +464,14 @@ export const properties_to_save = [
|
||||
'middle_name',
|
||||
'family_name',
|
||||
'designations',
|
||||
|
||||
'professional_title',
|
||||
'professional_title_override',
|
||||
|
||||
'full_name',
|
||||
'full_name_override',
|
||||
|
||||
'affiliations',
|
||||
'affiliations_override',
|
||||
|
||||
'email',
|
||||
'email_override',
|
||||
|
||||
'address_line_1',
|
||||
'address_line_2',
|
||||
'address_line_3',
|
||||
@@ -594,9 +485,7 @@ export const properties_to_save = [
|
||||
'full_address',
|
||||
'location',
|
||||
'location_override',
|
||||
|
||||
'query_str',
|
||||
|
||||
'badge_type',
|
||||
'badge_type_code',
|
||||
'badge_type_override',
|
||||
@@ -604,11 +493,8 @@ export const properties_to_save = [
|
||||
'external_event_id',
|
||||
'external_id',
|
||||
'external_person_id',
|
||||
|
||||
'default_qry_string',
|
||||
|
||||
'alert',
|
||||
|
||||
'enable',
|
||||
'hide',
|
||||
'priority',
|
||||
@@ -617,15 +503,11 @@ export const properties_to_save = [
|
||||
'notes',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
|
||||
'print_count',
|
||||
'print_first_datetime',
|
||||
'print_last_datetime',
|
||||
|
||||
// Generated fields for sorting locally only
|
||||
'tmp_sort_1',
|
||||
'tmp_sort_2',
|
||||
|
||||
'person_external_id',
|
||||
'person_external_sys_id',
|
||||
'person_given_name',
|
||||
@@ -639,7 +521,6 @@ export const properties_to_save = [
|
||||
|
||||
/**
|
||||
* NON-EXPORTED LOCAL HELPER
|
||||
* Processes a list of Aether objects by applying common and specific transformations.
|
||||
*/
|
||||
async function _process_generic_props<T extends Record<string, any>>({
|
||||
obj_li,
|
||||
@@ -652,39 +533,24 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
log_lvl?: number;
|
||||
specific_processor?: (obj: T) => Promise<T> | T;
|
||||
}): Promise<T[]> {
|
||||
if (log_lvl > 0) {
|
||||
console.log(
|
||||
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
|
||||
);
|
||||
}
|
||||
|
||||
if (!obj_li || obj_li.length === 0) {
|
||||
if (log_lvl > 0) console.log('No objects to process.');
|
||||
return [];
|
||||
}
|
||||
if (!obj_li || obj_li.length === 0) return [];
|
||||
|
||||
const processed_obj_li: T[] = [];
|
||||
|
||||
for (const original_obj of obj_li) {
|
||||
let processed_obj = { ...original_obj };
|
||||
|
||||
// --- Common Transformations ---
|
||||
|
||||
// 1. Standardize ID and other '_random' fields
|
||||
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
|
||||
for (const key in processed_obj) {
|
||||
if (key.endsWith('_random')) {
|
||||
const newKey = key.slice(0, -7); // Remove '_random' suffix
|
||||
const newKey = key.slice(0, -7);
|
||||
(processed_obj as any)[newKey] = processed_obj[key];
|
||||
}
|
||||
}
|
||||
// Ensure 'id' is set from '[obj_type]_id_random'
|
||||
const randomIdKey = `${obj_type}_id_random`;
|
||||
if (processed_obj[randomIdKey]) {
|
||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||
}
|
||||
|
||||
// 2. Create common computed properties for client-side sorting.
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
@@ -694,7 +560,6 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
// --- Specific Transformations ---
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
}
|
||||
@@ -720,20 +585,10 @@ export async function process_ae_obj__event_badge_props({
|
||||
obj_type: 'event_badge',
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
// If the event_id isn't returned from the API, add it here.
|
||||
if (event_id) {
|
||||
if (!obj.event_id) obj.event_id = event_id;
|
||||
if (!obj.event_id_random) obj.event_id_random = event_id;
|
||||
}
|
||||
|
||||
// Event badge-specific computed sort fields, overriding generic ones if needed
|
||||
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
|
||||
obj.sort?.toString().padStart(3, '0') ?? ''
|
||||
}_${obj.updated_on ?? obj.created_on}`;
|
||||
obj.tmp_sort_2 = `${obj.print_count ?? '0'}_${obj.priority ? '1' : '0'}_${
|
||||
obj.sort?.toString().padStart(3, '0') ?? ''
|
||||
}_${obj.given_name ?? ''}_${obj.family_name ?? ''}_${obj.updated_on ?? obj.created_on}`;
|
||||
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -361,7 +361,7 @@ export async function update_ae_obj__event_session({
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
||||
// Updated 2026-01-21 to Restore Full Aether Search logic
|
||||
export async function search__event_session({
|
||||
api_cfg,
|
||||
event_id,
|
||||
@@ -405,16 +405,14 @@ export async function search__event_session({
|
||||
console.log(`*** search__event_session() *** [V3] event_id=${event_id} ft=${fulltext_search_qry_str}`);
|
||||
}
|
||||
|
||||
// 1. Build the search query body
|
||||
const search_query: any = {
|
||||
q: '', // Default query string
|
||||
q: '',
|
||||
and: [{ field: 'event_id_random', op: 'eq', value: event_id }]
|
||||
};
|
||||
|
||||
// 2. Build the params object for special flags (the 'params_json' equivalent)
|
||||
const params: key_val = {};
|
||||
|
||||
// 3. Restore the Fulltext Logic
|
||||
// Restore Fulltext logic
|
||||
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
|
||||
params['ft_qry'] = {};
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
|
||||
@@ -425,7 +423,7 @@ export async function search__event_session({
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Restore the 'Like' Logic
|
||||
// Restore Like logic
|
||||
if (like_search_qry_str || like_presentation_search_qry_str || like_presenter_search_qry_str || like_poc_name_qry_str) {
|
||||
params['lk_qry'] = {};
|
||||
if (like_search_qry_str) params['lk_qry']['default_qry_str'] = like_search_qry_str;
|
||||
@@ -449,7 +447,7 @@ export async function search__event_session({
|
||||
obj_type: 'event_session',
|
||||
search_query,
|
||||
order_by_li,
|
||||
params, // Pass the special flags into the V3 params
|
||||
params, // Important: pass through special Aether params
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
|
||||
Reference in New Issue
Block a user