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