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