Browse Source

start adding the SQL approach to files, also using the Dexie approach if desired

pull/137/head
Trent Larson 2 weeks ago
parent
commit
11f2527b04
  1. 15
      doc/secure-storage-implementation.md
  2. 3
      src/constants/app.ts
  3. 65
      src/db/databaseUtil.ts
  4. 9
      src/libs/endorserServer.ts
  5. 137
      src/views/AccountViewView.vue

15
doc/secure-storage-implementation.md

@ -209,12 +209,8 @@ When converting from Dexie.js to SQL-based implementation, follow these patterns
``` ```
Key Considerations: Key Considerations:
1. Always use parameterized queries to prevent SQL injection - Use the `generateUpdateStatement` helper for update operations
2. Use the `generateUpdateStatement` helper for update operations - Use the `mapColumnsToValues` helper for processing query results
3. Use the `mapColumnsToValues` helper for processing query results
4. Handle transactions explicitly for batch operations
5. Use appropriate error handling with the StorageError class
6. Consider platform-specific capabilities when implementing features
Example Migration: Example Migration:
```typescript ```typescript
@ -238,7 +234,12 @@ export async function updateSettings(settings: Settings): Promise<void> {
Remember to: Remember to:
- Create database access code to use the platform service, putting it in front of the Dexie version - Create database access code to use the platform service, putting it in front of the Dexie version
- Instead of removing Dexie-specific code, keep it; if we use the results of the query, then check the USE_DEXIE_DB from app.ts and if it's true then use that instead of the SQL code. - Instead of removing Dexie-specific code, keep it.
- For creates & updates & deletes, the duplicate code is fine.
- For queries where we use the results, make the setting from SQL into a 'let' variable, then wrap the Dexie code in a check for USE_DEXIE_DB from app.ts and if it's true then use that result instead of the SQL code's result.
- Test thoroughly after migration - Test thoroughly after migration
- Consider data migration needs, and warn if there are any potential migration problems - Consider data migration needs, and warn if there are any potential migration problems

3
src/constants/app.ts

@ -7,6 +7,7 @@ export enum AppString {
// This is used in titles and verbiage inside the app. // This is used in titles and verbiage inside the app.
// There is also an app name without spaces, for packaging in the package.json file used in the manifest. // There is also an app name without spaces, for packaging in the package.json file used in the manifest.
APP_NAME = "Time Safari", APP_NAME = "Time Safari",
APP_NAME_NO_SPACES = "TimeSafari",
PROD_ENDORSER_API_SERVER = "https://api.endorser.ch", PROD_ENDORSER_API_SERVER = "https://api.endorser.ch",
TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch", TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch",
@ -50,7 +51,7 @@ export const IMAGE_TYPE_PROFILE = "profile";
export const PASSKEYS_ENABLED = export const PASSKEYS_ENABLED =
!!import.meta.env.VITE_PASSKEYS_ENABLED || false; !!import.meta.env.VITE_PASSKEYS_ENABLED || false;
export const USE_DEXIE_DB = true; export const USE_DEXIE_DB = false;
/** /**
* The possible values for "group" and "type" are in App.vue. * The possible values for "group" and "type" are in App.vue.

65
src/db/databaseUtil.ts

@ -26,38 +26,6 @@ export async function updateDefaultSettings(
} }
} }
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( export async function updateAccountSettings(
accountDid: string, accountDid: string,
settingsChanges: Settings, settingsChanges: Settings,
@ -92,6 +60,39 @@ export async function updateAccountSettings(
} }
} }
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 : {};
const overrideSettingsFiltered = Object.fromEntries(Object.entries(overrideSettings).filter(([_, v]) => v !== null));
return { ...defaultSettings, ...overrideSettingsFiltered };
}
}
export async function logToDb(message: string): Promise<void> { export async function logToDb(message: string): Promise<void> {
const platform = PlatformServiceFactory.getInstance(); const platform = PlatformServiceFactory.getInstance();
const todayKey = new Date().toDateString(); const todayKey = new Date().toDateString();

9
src/libs/endorserServer.ts

@ -26,6 +26,7 @@ import {
DEFAULT_IMAGE_API_SERVER, DEFAULT_IMAGE_API_SERVER,
NotificationIface, NotificationIface,
APP_SERVER, APP_SERVER,
USE_DEXIE_DB,
} from "../constants/app"; } from "../constants/app";
import { Contact } from "../db/tables/contacts"; import { Contact } from "../db/tables/contacts";
import { accessToken, deriveAddress, nextDerivationPath } from "../libs/crypto"; import { accessToken, deriveAddress, nextDerivationPath } from "../libs/crypto";
@ -49,6 +50,7 @@ import {
CreateAndSubmitClaimResult, CreateAndSubmitClaimResult,
} from "../interfaces"; } from "../interfaces";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/** /**
* Standard context for schema.org data * Standard context for schema.org data
@ -1363,8 +1365,15 @@ export async function setVisibilityUtil(
if (resp.status === 200) { if (resp.status === 200) {
const success = resp.data.success; const success = resp.data.success;
if (success) { if (success) {
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET seesMe = ? WHERE did = ?",
[visibility, contact.did],
);
if (USE_DEXIE_DB) {
db.contacts.update(contact.did, { seesMe: visibility }); db.contacts.update(contact.did, { seesMe: visibility });
} }
}
return { success }; return { success };
} else { } else {
logger.error( logger.error(

137
src/views/AccountViewView.vue

@ -999,6 +999,7 @@ import {
DEFAULT_PUSH_SERVER, DEFAULT_PUSH_SERVER,
IMAGE_TYPE_PROFILE, IMAGE_TYPE_PROFILE,
NotificationIface, NotificationIface,
USE_DEXIE_DB,
} from "../constants/app"; } from "../constants/app";
import { import {
db, db,
@ -1012,6 +1013,7 @@ import {
DEFAULT_PASSKEY_EXPIRATION_MINUTES, DEFAULT_PASSKEY_EXPIRATION_MINUTES,
MASTER_SETTINGS_KEY, MASTER_SETTINGS_KEY,
} from "../db/tables/settings"; } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import { import {
clearPasskeyToken, clearPasskeyToken,
EndorserRateLimits, EndorserRateLimits,
@ -1030,6 +1032,7 @@ import {
} from "../libs/util"; } from "../libs/util";
import { UserProfile } from "@/libs/partnerServer"; import { UserProfile } from "@/libs/partnerServer";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
const inputImportFileNameRef = ref<Blob>(); const inputImportFileNameRef = ref<Blob>();
@ -1145,9 +1148,14 @@ export default class AccountViewView extends Vue {
if (error.status === 404) { if (error.status === 404) {
// this is ok: the profile is not yet created // this is ok: the profile is not yet created
} else { } else {
databaseUtil.logConsoleAndDb(
"Error loading profile: " + errorStringForLog(error),
);
if (USE_DEXIE_DB) {
logConsoleAndDb( logConsoleAndDb(
"Error loading profile: " + errorStringForLog(error), "Error loading profile: " + errorStringForLog(error),
); );
}
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -1224,8 +1232,12 @@ export default class AccountViewView extends Vue {
* Initializes component state with values from the database or defaults. * Initializes component state with values from the database or defaults.
*/ */
async initializeState() { async initializeState() {
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
await db.open(); await db.open();
const settings = await retrieveSettingsForActiveAccount(); settings = await retrieveSettingsForActiveAccount();
}
console.log("activeDid", settings.activeDid, "settings", settings);
this.activeDid = settings.activeDid || ""; this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || ""; this.apiServer = settings.apiServer || "";
@ -1268,43 +1280,68 @@ export default class AccountViewView extends Vue {
async toggleShowContactAmounts() { async toggleShowContactAmounts() {
this.showContactGives = !this.showContactGives; this.showContactGives = !this.showContactGives;
await databaseUtil.updateDefaultSettings({
showContactGivesInline: this.showContactGives,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
showContactGivesInline: this.showContactGives, showContactGivesInline: this.showContactGives,
}); });
} }
}
async toggleShowGeneralAdvanced() { async toggleShowGeneralAdvanced() {
this.showGeneralAdvanced = !this.showGeneralAdvanced; this.showGeneralAdvanced = !this.showGeneralAdvanced;
await databaseUtil.updateDefaultSettings({
showGeneralAdvanced: this.showGeneralAdvanced,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
showGeneralAdvanced: this.showGeneralAdvanced, showGeneralAdvanced: this.showGeneralAdvanced,
}); });
} }
}
async toggleProdWarning() { async toggleProdWarning() {
this.warnIfProdServer = !this.warnIfProdServer; this.warnIfProdServer = !this.warnIfProdServer;
await databaseUtil.updateDefaultSettings({
warnIfProdServer: this.warnIfProdServer,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
warnIfProdServer: this.warnIfProdServer, warnIfProdServer: this.warnIfProdServer,
}); });
} }
}
async toggleTestWarning() { async toggleTestWarning() {
this.warnIfTestServer = !this.warnIfTestServer; this.warnIfTestServer = !this.warnIfTestServer;
await databaseUtil.updateDefaultSettings({
warnIfTestServer: this.warnIfTestServer,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
warnIfTestServer: this.warnIfTestServer, warnIfTestServer: this.warnIfTestServer,
}); });
} }
}
async toggleShowShortcutBvc() { async toggleShowShortcutBvc() {
this.showShortcutBvc = !this.showShortcutBvc; this.showShortcutBvc = !this.showShortcutBvc;
await databaseUtil.updateDefaultSettings({
showShortcutBvc: this.showShortcutBvc,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
showShortcutBvc: this.showShortcutBvc, showShortcutBvc: this.showShortcutBvc,
}); });
} }
}
readableDate(timeStr: string) { readableDate(timeStr: string) {
return timeStr ? timeStr.substring(0, timeStr.indexOf("T")) : "?"; return timeStr ? timeStr.substring(0, timeStr.indexOf("T")) : "?";
@ -1314,9 +1351,18 @@ export default class AccountViewView extends Vue {
* Processes the identity and updates the component's state. * Processes the identity and updates the component's state.
*/ */
async processIdentity() { async processIdentity() {
const account: Account | undefined = await retrieveAccountMetadata( const platformService = PlatformServiceFactory.getInstance();
const dbAccount = await platformService.dbQuery("SELECT * FROM accounts WHERE did = ?", [this.activeDid]);
console.log("activeDid", this.activeDid, "dbAccount", dbAccount);
let account: Account | undefined = undefined;
if (dbAccount) {
account = databaseUtil.mapColumnsToValues(dbAccount.columns, dbAccount.values)[0] as Account;
}
if (USE_DEXIE_DB) {
account = await retrieveAccountMetadata(
this.activeDid, this.activeDid,
); );
}
if (account?.identity) { if (account?.identity) {
const identity = JSON.parse(account.identity as string) as IIdentifier; const identity = JSON.parse(account.identity as string) as IIdentifier;
this.publicHex = identity.keys[0].publicKeyHex; this.publicHex = identity.keys[0].publicKeyHex;
@ -1359,9 +1405,14 @@ export default class AccountViewView extends Vue {
this.$refs.pushNotificationPermission as PushNotificationPermission this.$refs.pushNotificationPermission as PushNotificationPermission
).open(DAILY_CHECK_TITLE, async (success: boolean, timeText: string) => { ).open(DAILY_CHECK_TITLE, async (success: boolean, timeText: string) => {
if (success) { if (success) {
await databaseUtil.updateDefaultSettings({
notifyingNewActivityTime: timeText,
});
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
notifyingNewActivityTime: timeText, notifyingNewActivityTime: timeText,
}); });
}
this.notifyingNewActivity = true; this.notifyingNewActivity = true;
this.notifyingNewActivityTime = timeText; this.notifyingNewActivityTime = timeText;
} }
@ -1375,9 +1426,14 @@ export default class AccountViewView extends Vue {
text: "", // unused, only here to satisfy type check text: "", // unused, only here to satisfy type check
callback: async (success) => { callback: async (success) => {
if (success) { if (success) {
await databaseUtil.updateDefaultSettings({
notifyingNewActivityTime: "",
});
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
notifyingNewActivityTime: "", notifyingNewActivityTime: "",
}); });
}
this.notifyingNewActivity = false; this.notifyingNewActivity = false;
this.notifyingNewActivityTime = ""; this.notifyingNewActivityTime = "";
} }
@ -1419,10 +1475,16 @@ export default class AccountViewView extends Vue {
DIRECT_PUSH_TITLE, DIRECT_PUSH_TITLE,
async (success: boolean, timeText: string, message?: string) => { async (success: boolean, timeText: string, message?: string) => {
if (success) { if (success) {
await databaseUtil.updateDefaultSettings({
notifyingReminderMessage: message,
notifyingReminderTime: timeText,
});
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
notifyingReminderMessage: message, notifyingReminderMessage: message,
notifyingReminderTime: timeText, notifyingReminderTime: timeText,
}); });
}
this.notifyingReminder = true; this.notifyingReminder = true;
this.notifyingReminderMessage = message || ""; this.notifyingReminderMessage = message || "";
this.notifyingReminderTime = timeText; this.notifyingReminderTime = timeText;
@ -1438,10 +1500,16 @@ export default class AccountViewView extends Vue {
text: "", // unused, only here to satisfy type check text: "", // unused, only here to satisfy type check
callback: async (success) => { callback: async (success) => {
if (success) { if (success) {
await databaseUtil.updateDefaultSettings({
notifyingReminderMessage: "",
notifyingReminderTime: "",
});
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
notifyingReminderMessage: "", notifyingReminderMessage: "",
notifyingReminderTime: "", notifyingReminderTime: "",
}); });
}
this.notifyingReminder = false; this.notifyingReminder = false;
this.notifyingReminderMessage = ""; this.notifyingReminderMessage = "";
this.notifyingReminderTime = ""; this.notifyingReminderTime = "";
@ -1455,30 +1523,47 @@ export default class AccountViewView extends Vue {
public async toggleHideRegisterPromptOnNewContact() { public async toggleHideRegisterPromptOnNewContact() {
const newSetting = !this.hideRegisterPromptOnNewContact; const newSetting = !this.hideRegisterPromptOnNewContact;
await databaseUtil.updateDefaultSettings({
hideRegisterPromptOnNewContact: newSetting,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: newSetting, hideRegisterPromptOnNewContact: newSetting,
}); });
}
this.hideRegisterPromptOnNewContact = newSetting; this.hideRegisterPromptOnNewContact = newSetting;
} }
public async updatePasskeyExpiration() { public async updatePasskeyExpiration() {
await databaseUtil.updateDefaultSettings({
passkeyExpirationMinutes: this.passkeyExpirationMinutes,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
passkeyExpirationMinutes: this.passkeyExpirationMinutes, passkeyExpirationMinutes: this.passkeyExpirationMinutes,
}); });
}
clearPasskeyToken(); clearPasskeyToken();
this.passkeyExpirationDescription = tokenExpiryTimeDescription(); this.passkeyExpirationDescription = tokenExpiryTimeDescription();
} }
public async turnOffNotifyingFlags() { public async turnOffNotifyingFlags() {
// should tell the push server as well // should tell the push server as well
await databaseUtil.updateDefaultSettings({
notifyingNewActivityTime: "",
notifyingReminderMessage: "",
notifyingReminderTime: "",
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
notifyingNewActivityTime: "", notifyingNewActivityTime: "",
notifyingReminderMessage: "", notifyingReminderMessage: "",
notifyingReminderTime: "", notifyingReminderTime: "",
}); });
}
this.notifyingNewActivity = false; this.notifyingNewActivity = false;
this.notifyingNewActivityTime = ""; this.notifyingNewActivityTime = "";
this.notifyingReminder = false; this.notifyingReminder = false;
@ -1518,8 +1603,11 @@ export default class AccountViewView extends Vue {
* @returns {Promise<Blob>} The generated blob object. * @returns {Promise<Blob>} The generated blob object.
*/ */
private async generateDatabaseBlob(): Promise<Blob> { private async generateDatabaseBlob(): Promise<Blob> {
if (USE_DEXIE_DB) {
return await db.export({ prettyJson: true }); return await db.export({ prettyJson: true });
} }
throw new Error("Not implemented");
}
/** /**
* Creates a temporary URL for a blob object. * Creates a temporary URL for a blob object.
@ -1539,7 +1627,7 @@ export default class AccountViewView extends Vue {
private downloadDatabaseBackup(url: string) { private downloadDatabaseBackup(url: string) {
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement; const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
downloadAnchor.href = url; downloadAnchor.href = url;
downloadAnchor.download = `${db.name}-backup.json`; downloadAnchor.download = `${AppString.APP_NAME_NO_SPACES}-backup.json`;
downloadAnchor.click(); // doesn't work for some browsers, eg. DuckDuckGo downloadAnchor.click(); // doesn't work for some browsers, eg. DuckDuckGo
} }
@ -1620,6 +1708,7 @@ export default class AccountViewView extends Vue {
*/ */
async submitImportFile() { async submitImportFile() {
if (inputImportFileNameRef.value != null) { if (inputImportFileNameRef.value != null) {
if (USE_DEXIE_DB) {
await db await db
.delete() .delete()
.then(async () => { .then(async () => {
@ -1640,6 +1729,9 @@ export default class AccountViewView extends Vue {
-1, -1,
); );
}); });
} else {
throw new Error("Not implemented");
}
} }
} }
@ -1727,7 +1819,13 @@ export default class AccountViewView extends Vue {
if (!this.isRegistered) { if (!this.isRegistered) {
// the user was not known to be registered, but now they are (because we got no error) so let's record it // the user was not known to be registered, but now they are (because we got no error) so let's record it
try { try {
await updateAccountSettings(did, { isRegistered: true }); await databaseUtil.updateAccountSettings(did, { isRegistered: true });
if (USE_DEXIE_DB) {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
isRegistered: true,
});
}
this.isRegistered = true; this.isRegistered = true;
} catch (err) { } catch (err) {
logger.error("Got an error updating settings:", err); logger.error("Got an error updating settings:", err);
@ -1787,26 +1885,41 @@ export default class AccountViewView extends Vue {
} }
async onClickSaveApiServer() { async onClickSaveApiServer() {
await databaseUtil.updateDefaultSettings({
apiServer: this.apiServerInput,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
apiServer: this.apiServerInput, apiServer: this.apiServerInput,
}); });
}
this.apiServer = this.apiServerInput; this.apiServer = this.apiServerInput;
} }
async onClickSavePartnerServer() { async onClickSavePartnerServer() {
await databaseUtil.updateDefaultSettings({
partnerApiServer: this.partnerApiServerInput,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
partnerApiServer: this.partnerApiServerInput, partnerApiServer: this.partnerApiServerInput,
}); });
}
this.partnerApiServer = this.partnerApiServerInput; this.partnerApiServer = this.partnerApiServerInput;
} }
async onClickSavePushServer() { async onClickSavePushServer() {
await databaseUtil.updateDefaultSettings({
webPushServer: this.webPushServerInput,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
webPushServer: this.webPushServerInput, webPushServer: this.webPushServerInput,
}); });
}
this.webPushServer = this.webPushServerInput; this.webPushServer = this.webPushServerInput;
this.$notify( this.$notify(
{ {
@ -1822,10 +1935,15 @@ export default class AccountViewView extends Vue {
openImageDialog() { openImageDialog() {
(this.$refs.imageMethodDialog as ImageMethodDialog).open( (this.$refs.imageMethodDialog as ImageMethodDialog).open(
async (imgUrl) => { async (imgUrl) => {
await databaseUtil.updateDefaultSettings({
profileImageUrl: imgUrl,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
profileImageUrl: imgUrl, profileImageUrl: imgUrl,
}); });
}
this.profileImageUrl = imgUrl; this.profileImageUrl = imgUrl;
//console.log("Got image URL:", imgUrl); //console.log("Got image URL:", imgUrl);
}, },
@ -1886,10 +2004,15 @@ export default class AccountViewView extends Vue {
// keep the imageUrl in localStorage so the user can try again if they want // keep the imageUrl in localStorage so the user can try again if they want
} }
await databaseUtil.updateDefaultSettings({
profileImageUrl: undefined,
});
if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
profileImageUrl: undefined, profileImageUrl: undefined,
}); });
}
this.profileImageUrl = undefined; this.profileImageUrl = undefined;
} catch (error) { } catch (error) {
@ -1978,7 +2101,10 @@ export default class AccountViewView extends Vue {
throw Error("Profile not saved"); throw Error("Profile not saved");
} }
} catch (error) { } catch (error) {
databaseUtil.logConsoleAndDb("Error saving profile: " + errorStringForLog(error));
if (USE_DEXIE_DB) {
logConsoleAndDb("Error saving profile: " + errorStringForLog(error)); logConsoleAndDb("Error saving profile: " + errorStringForLog(error));
}
const errorMessage: string = const errorMessage: string =
error.response?.data?.error?.message || error.response?.data?.error?.message ||
error.response?.data?.error || error.response?.data?.error ||
@ -2068,7 +2194,10 @@ export default class AccountViewView extends Vue {
throw Error("Profile not deleted"); throw Error("Profile not deleted");
} }
} catch (error) { } catch (error) {
databaseUtil.logConsoleAndDb("Error deleting profile: " + errorStringForLog(error));
if (USE_DEXIE_DB) {
logConsoleAndDb("Error deleting profile: " + errorStringForLog(error)); logConsoleAndDb("Error deleting profile: " + errorStringForLog(error));
}
const errorMessage: string = const errorMessage: string =
error.response?.data?.error?.message || error.response?.data?.error?.message ||
error.response?.data?.error || error.response?.data?.error ||

Loading…
Cancel
Save