From fb724411d3aead406615ce14304c0ca065bc3d61 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Mon, 16 Feb 2026 16:13:04 -0500 Subject: [PATCH] Initialized Activity Log IndexedDB infrastructure and refactored Jitsi reports. Added 'activity_log' table to Dexie 'ae_core_db' (v4) to support local caching of tracking data. Implemented 'process_ae_obj__activity_log_props' with robust timestamp fallbacks. Refactored 'qry__jitsi_report' to follow the Frontier module pattern, ensuring consistent V3 search and local cache synchronization. --- src/lib/ae_core/ae_core__activity_log.ts | 100 +++++++++++++++++++++++ src/lib/ae_core/db_core.ts | 16 +++- src/lib/ae_reports/reports_functions.ts | 80 ++++++++++++------ 3 files changed, 169 insertions(+), 27 deletions(-) diff --git a/src/lib/ae_core/ae_core__activity_log.ts b/src/lib/ae_core/ae_core__activity_log.ts index 4211a6aa..ab82f89e 100644 --- a/src/lib/ae_core/ae_core__activity_log.ts +++ b/src/lib/ae_core/ae_core__activity_log.ts @@ -268,4 +268,104 @@ export async function qry__activity_log({ } +// Updated 2026-02-16 +export const properties_to_save = [ + 'id', + 'activity_log_id', + 'activity_log_id_random', + 'account_id', + 'account_id_random', + 'person_id', + 'person_id_random', + 'user_id', + 'user_id_random', + 'external_client_id', + 'source', + 'object_type', + 'object_id', + 'object_id_random', + 'name', + 'action', + 'action_on_type', + 'action_on_id', + 'action_on_id_random', + 'description', + 'details', + 'other_json', + 'meta_json', + 'enable', + 'hide', + 'priority', + 'sort', + 'group', + 'notes', + 'created_on', + 'updated_on', + 'tmp_sort_1', + 'tmp_sort_2', + 'tmp_sort_3' +]; + +async function _process_generic_props>({ + obj_li, + obj_type, + log_lvl = 0, + specific_processor +}: { + obj_li: T[]; + obj_type: string; + log_lvl?: number; + specific_processor?: (obj: T) => Promise | T; +}): Promise { + 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 }; + + for (const key in processed_obj) { + if (key.endsWith('_random')) { + const newKey = key.slice(0, -7); + (processed_obj as any)[newKey] = processed_obj[key]; + } + } + const randomIdKey = `${obj_type}_id_random`; + if (processed_obj[randomIdKey]) { + (processed_obj as any).id = processed_obj[randomIdKey]; + } + + const group = processed_obj.group ?? '0'; + const priority = processed_obj.priority ? 1 : 0; + const sort = processed_obj.sort ?? '0'; + const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString(); + const name = processed_obj.name ?? ''; + + (processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`; + (processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`; + + if (specific_processor) { + processed_obj = await Promise.resolve(specific_processor(processed_obj)); + } + + processed_obj_li.push(processed_obj as T); + } + + return processed_obj_li; +} + +export async function process_ae_obj__activity_log_props({ + obj_li, + log_lvl = 0 +}: { + obj_li: any[]; + log_lvl?: number; +}) { + return _process_generic_props({ + obj_li, + obj_type: 'activity_log', + log_lvl + }); +} + diff --git a/src/lib/ae_core/db_core.ts b/src/lib/ae_core/db_core.ts index bb99dfaa..e4d9f631 100644 --- a/src/lib/ae_core/db_core.ts +++ b/src/lib/ae_core/db_core.ts @@ -8,7 +8,8 @@ import type { ae_SiteDomain, ae_Address, ae_Contact, - ae_DataStore + ae_DataStore, + ae_ActivityLog } from '$lib/types/ae_types'; // li = list @@ -61,7 +62,7 @@ export interface Person extends ae_Person { address_id_random?: string; } -// Updated 2026-01-28 - Unified Types and added Data Store +// Updated 2026-02-16 - Added Activity Log export class MySubClassedDexie extends Dexie { file!: Table; person!: Table; @@ -72,10 +73,11 @@ export class MySubClassedDexie extends Dexie { address!: Table; contact!: Table; data_store!: Table; + activity_log!: Table; constructor() { super('ae_core_db'); - this.version(3).stores({ + this.version(4).stores({ file: ` id, hosted_file_id, hosted_file_id_random, hash_sha256, @@ -138,6 +140,14 @@ export class MySubClassedDexie extends Dexie { [code+for_type+for_id_random], [code+account_id_random+for_type], [code+account_id_random], + enable, hide, priority, sort, group, created_on, updated_on`, + + activity_log: ` + id, activity_log_id, activity_log_id_random, + account_id, account_id_random, + person_id_random, user_id_random, + external_client_id, object_type, object_id_random, + name, action, enable, hide, priority, sort, group, created_on, updated_on` }); } diff --git a/src/lib/ae_reports/reports_functions.ts b/src/lib/ae_reports/reports_functions.ts index 44d07418..587bc9f5 100644 --- a/src/lib/ae_reports/reports_functions.ts +++ b/src/lib/ae_reports/reports_functions.ts @@ -1,61 +1,91 @@ import type { key_val } from '$lib/stores/ae_stores'; import { api } from '$lib/api/api'; +import { process_ae_obj__activity_log_props, properties_to_save } from '$lib/ae_core/ae_core__activity_log'; +import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie'; +import { db_core } from '$lib/ae_core/db_core'; /** * @description Queries all Jitsi-related activity logs and processes them into a structured report, * grouped by meeting ID. * @param api_cfg The API configuration object. * @param account_id The account ID to query against. + * @param enabled Filter by enabled status. + * @param hidden Filter by hidden status. + * @param limit Maximum number of logs to fetch. + * @param try_cache Whether to sync the raw logs to the local activity_log table. * @param log_lvl The logging level. * @returns A structured array of meeting report objects. */ -export async function load_jitsi_report({ +export async function qry__jitsi_report({ api_cfg, account_id, + enabled = 'all', + hidden = 'all', + limit = 500, + try_cache = true, log_lvl = 0 }: { api_cfg: any; account_id: string; + enabled?: 'enabled' | 'all' | 'not_enabled' | undefined; + hidden?: 'hidden' | 'all' | 'not_hidden' | undefined; + limit?: number; + try_cache?: boolean; log_lvl?: number; }) { - if (log_lvl) console.log('*** load_jitsi_report() ***'); + if (log_lvl) console.log('*** qry__jitsi_report() ***'); // Step 1: Query all relevant activity logs from the API. - const params_json = { - or_qry: [ - { - field: 'name', - operator: '=', - value: 'jitsi_meeting_stats_update' - }, - { - field: 'name', - operator: '=', - value: 'jitsi_meeting_event' - } + const search_query = { + or: [ + { field: 'name', op: 'eq', value: 'jitsi_meeting_stats_update' }, + { field: 'name', op: 'eq', value: 'jitsi_meeting_event' }, + { field: 'name', op: 'eq', value: 'jitsi_meeting_stats' } + ], + and: [ + { field: 'account_id_random', op: 'eq', value: account_id } ] }; - const flat_log_list = await api.get_ae_obj_li_for_obj_id_crud_v2({ + const result = await api.search_ae_obj_v3({ api_cfg: api_cfg, obj_type: 'activity_log', - for_obj_type: 'account', - for_obj_id: account_id, - // use_alt_tbl: true, - // use_alt_mdl: true, - enabled: 'all', - hidden: 'all', - limit: 500, // Fetch a reasonable number of recent logs - params_json: params_json, + search_query, headers: { 'x-account-id': account_id }, - log_lvl: 2 + enabled, + hidden, + limit, + log_lvl: log_lvl }); + // Handle potential V3 API envelope + let flat_log_list: any[] = []; + if (Array.isArray(result)) { + flat_log_list = result; + } else if (result && typeof result === 'object' && Array.isArray((result as any).data)) { + flat_log_list = (result as any).data; + } + if (!flat_log_list || !Array.isArray(flat_log_list) || flat_log_list.length === 0) { if (log_lvl) console.log('No Jitsi activity logs found or error occurred.'); return []; } + // Frontier Standard: Process and Save to local cache + if (try_cache) { + const processed_obj_li = await process_ae_obj__activity_log_props({ + obj_li: flat_log_list, + log_lvl: log_lvl + }); + await db_save_ae_obj_li__ae_obj({ + db_instance: db_core, + table_name: 'activity_log', + obj_li: processed_obj_li, + properties_to_save: properties_to_save, + log_lvl: log_lvl + }); + } + // Step 2: Process the flat list into a structured report. const meetings = new Map(); @@ -112,3 +142,5 @@ export async function load_jitsi_report({ return final_report; } + +export const load_jitsi_report = qry__jitsi_report;