8 changed files with 468 additions and 28 deletions
			
			
		@ -0,0 +1,196 @@ | 
				
			|||||
 | 
					import { PlatformServiceFactory } from "@/services/PlatformServiceFactory"; | 
				
			||||
 | 
					import { MASTER_SETTINGS_KEY, Settings } from "./tables/settings"; | 
				
			||||
 | 
					import { logger } from "@/utils/logger"; | 
				
			||||
 | 
					import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app"; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export async function updateDefaultSettings( | 
				
			||||
 | 
					  settingsChanges: Settings, | 
				
			||||
 | 
					): Promise<boolean> { | 
				
			||||
 | 
					  delete settingsChanges.accountDid; // just in case
 | 
				
			||||
 | 
					  // ensure there is no "id" that would override the key
 | 
				
			||||
 | 
					  delete settingsChanges.id; | 
				
			||||
 | 
					  try { | 
				
			||||
 | 
					    const platformService = PlatformServiceFactory.getInstance(); | 
				
			||||
 | 
					    const { sql, params } = generateUpdateStatement(settingsChanges, "settings", "id = ?", [MASTER_SETTINGS_KEY]); | 
				
			||||
 | 
					    const result = await platformService.dbExec(sql, params); | 
				
			||||
 | 
					    return result.changes === 1; | 
				
			||||
 | 
					  } catch (error) { | 
				
			||||
 | 
					    logger.error("Error updating default settings:", error); | 
				
			||||
 | 
					    if (error instanceof Error) { | 
				
			||||
 | 
					      throw error; // Re-throw if it's already an Error with a message
 | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					      throw new Error( | 
				
			||||
 | 
					        `Failed to update settings. We recommend you try again or restart the app.`, | 
				
			||||
 | 
					      ); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const DEFAULT_SETTINGS: Settings = { | 
				
			||||
 | 
					  id: MASTER_SETTINGS_KEY, | 
				
			||||
 | 
					  activeDid: undefined, | 
				
			||||
 | 
					  apiServer: DEFAULT_ENDORSER_API_SERVER, | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// retrieves default settings
 | 
				
			||||
 | 
					export async function retrieveSettingsForDefaultAccount(): Promise<Settings> { | 
				
			||||
 | 
					  const platform = PlatformServiceFactory.getInstance(); | 
				
			||||
 | 
					  const result = await platform.dbQuery("SELECT * FROM settings WHERE id = ?", MASTER_SETTINGS_KEY) | 
				
			||||
 | 
					  if (!result) { | 
				
			||||
 | 
					    return DEFAULT_SETTINGS; | 
				
			||||
 | 
					  } else { | 
				
			||||
 | 
					    return mapColumnsToValues(result.columns, result.values)[0] as Settings; | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export async function retrieveSettingsForActiveAccount(): Promise<Settings> { | 
				
			||||
 | 
					  const defaultSettings = await retrieveSettingsForDefaultAccount(); | 
				
			||||
 | 
					  if (!defaultSettings.activeDid) { | 
				
			||||
 | 
					    return defaultSettings; | 
				
			||||
 | 
					  } else { | 
				
			||||
 | 
					    const platform = PlatformServiceFactory.getInstance(); | 
				
			||||
 | 
					    const result = await platform.dbQuery( | 
				
			||||
 | 
					      "SELECT * FROM settings WHERE accountDid = ?", | 
				
			||||
 | 
					      [defaultSettings.activeDid] | 
				
			||||
 | 
					    ); | 
				
			||||
 | 
					    const overrideSettings = result ? mapColumnsToValues(result.columns, result.values)[0] as Settings : {}; | 
				
			||||
 | 
					    return { ...defaultSettings, ...overrideSettings }; | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export async function updateAccountSettings( | 
				
			||||
 | 
					  accountDid: string, | 
				
			||||
 | 
					  settingsChanges: Settings, | 
				
			||||
 | 
					): Promise<boolean> { | 
				
			||||
 | 
					  settingsChanges.accountDid = accountDid; | 
				
			||||
 | 
					  delete settingsChanges.id; // key off account, not ID
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const platform = PlatformServiceFactory.getInstance(); | 
				
			||||
 | 
					   | 
				
			||||
 | 
					  // First try to update existing record
 | 
				
			||||
 | 
					  const { sql: updateSql, params: updateParams } = generateUpdateStatement( | 
				
			||||
 | 
					    settingsChanges, | 
				
			||||
 | 
					    "settings", | 
				
			||||
 | 
					    "accountDid = ?", | 
				
			||||
 | 
					    [accountDid] | 
				
			||||
 | 
					  ); | 
				
			||||
 | 
					   | 
				
			||||
 | 
					  const updateResult = await platform.dbExec(updateSql, updateParams); | 
				
			||||
 | 
					   | 
				
			||||
 | 
					  // If no record was updated, insert a new one
 | 
				
			||||
 | 
					  if (updateResult.changes === 1) { | 
				
			||||
 | 
					    return true; | 
				
			||||
 | 
					  } else { | 
				
			||||
 | 
					    const columns = Object.keys(settingsChanges); | 
				
			||||
 | 
					    const values = Object.values(settingsChanges); | 
				
			||||
 | 
					    const placeholders = values.map(() => '?').join(', '); | 
				
			||||
 | 
					     | 
				
			||||
 | 
					    const insertSql = `INSERT INTO settings (${columns.join(', ')}) VALUES (${placeholders})`; | 
				
			||||
 | 
					    const result = await platform.dbExec(insertSql, values); | 
				
			||||
 | 
					     | 
				
			||||
 | 
					    return result.changes === 1; | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export async function logToDb(message: string): Promise<void> { | 
				
			||||
 | 
					  const platform = PlatformServiceFactory.getInstance(); | 
				
			||||
 | 
					  const todayKey = new Date().toDateString(); | 
				
			||||
 | 
					   | 
				
			||||
 | 
					  // Check if we have any logs for today
 | 
				
			||||
 | 
					  const result = await platform.dbQuery( | 
				
			||||
 | 
					    "SELECT message FROM logs WHERE date = ?", | 
				
			||||
 | 
					    [todayKey] | 
				
			||||
 | 
					  ); | 
				
			||||
 | 
					   | 
				
			||||
 | 
					  if (!result || result.values.length === 0) { | 
				
			||||
 | 
					    // If no logs for today, clear all previous logs
 | 
				
			||||
 | 
					    await platform.dbExec("DELETE FROM logs"); | 
				
			||||
 | 
					     | 
				
			||||
 | 
					    // Insert new log
 | 
				
			||||
 | 
					    const fullMessage = `${new Date().toISOString()} ${message}`; | 
				
			||||
 | 
					    await platform.dbExec( | 
				
			||||
 | 
					      "INSERT INTO logs (date, message) VALUES (?, ?)", | 
				
			||||
 | 
					      [todayKey, fullMessage] | 
				
			||||
 | 
					    ); | 
				
			||||
 | 
					  } else { | 
				
			||||
 | 
					    // Append to existing log
 | 
				
			||||
 | 
					    const prevMessages = result.values[0][0] as string; | 
				
			||||
 | 
					    const fullMessage = `${prevMessages}\n${new Date().toISOString()} ${message}`; | 
				
			||||
 | 
					     | 
				
			||||
 | 
					    await platform.dbExec( | 
				
			||||
 | 
					      "UPDATE logs SET message = ? WHERE date = ?", | 
				
			||||
 | 
					      [fullMessage, todayKey] | 
				
			||||
 | 
					    ); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// similar method is in the sw_scripts/additional-scripts.js file
 | 
				
			||||
 | 
					export async function logConsoleAndDb( | 
				
			||||
 | 
					  message: string, | 
				
			||||
 | 
					  isError = false, | 
				
			||||
 | 
					): Promise<void> { | 
				
			||||
 | 
					  if (isError) { | 
				
			||||
 | 
					    logger.error(`${new Date().toISOString()} ${message}`); | 
				
			||||
 | 
					  } else { | 
				
			||||
 | 
					    logger.log(`${new Date().toISOString()} ${message}`); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					  await logToDb(message); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** | 
				
			||||
 | 
					 * Generates an SQL UPDATE statement and parameters from a model object. | 
				
			||||
 | 
					 * @param model The model object containing fields to update | 
				
			||||
 | 
					 * @param tableName The name of the table to update | 
				
			||||
 | 
					 * @param whereClause The WHERE clause for the update (e.g. "id = ?") | 
				
			||||
 | 
					 * @param whereParams Parameters for the WHERE clause | 
				
			||||
 | 
					 * @returns Object containing the SQL statement and parameters array | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					function generateUpdateStatement( | 
				
			||||
 | 
					  model: Record<string, any>, | 
				
			||||
 | 
					  tableName: string, | 
				
			||||
 | 
					  whereClause: string, | 
				
			||||
 | 
					  whereParams: any[] = [] | 
				
			||||
 | 
					): { sql: string; params: any[] } { | 
				
			||||
 | 
					  // Filter out undefined/null values and create SET clause
 | 
				
			||||
 | 
					  const setClauses: string[] = []; | 
				
			||||
 | 
					  const params: any[] = []; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  Object.entries(model).forEach(([key, value]) => { | 
				
			||||
 | 
					    if (value !== undefined) { | 
				
			||||
 | 
					      setClauses.push(`${key} = ?`); | 
				
			||||
 | 
					      params.push(value); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  if (setClauses.length === 0) { | 
				
			||||
 | 
					    throw new Error('No valid fields to update'); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const sql = `UPDATE ${tableName} SET ${setClauses.join(', ')} WHERE ${whereClause}`; | 
				
			||||
 | 
					   | 
				
			||||
 | 
					  return { | 
				
			||||
 | 
					    sql, | 
				
			||||
 | 
					    params: [...params, ...whereParams] | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** | 
				
			||||
 | 
					 * Maps an array of column names to an array of value arrays, creating objects where each column name | 
				
			||||
 | 
					 * is mapped to its corresponding value. | 
				
			||||
 | 
					 * @param columns Array of column names to use as object keys | 
				
			||||
 | 
					 * @param values Array of value arrays, where each inner array corresponds to one row of data | 
				
			||||
 | 
					 * @returns Array of objects where each object maps column names to their corresponding values | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					export function mapColumnsToValues( | 
				
			||||
 | 
					  columns: string[], | 
				
			||||
 | 
					  values: any[][] | 
				
			||||
 | 
					): Record<string, any>[] { | 
				
			||||
 | 
					  return values.map(row => { | 
				
			||||
 | 
					    const obj: Record<string, any> = {}; | 
				
			||||
 | 
					    columns.forEach((column, index) => { | 
				
			||||
 | 
					      obj[column] = row[index]; | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					    return obj; | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue