Browse Source

add SQL DB access to everywhere we are using the DB, up to the "C" files

pull/137/head
Trent Larson 2 weeks ago
parent
commit
7de4125eb7
  1. 27
      src/components/FeedFilters.vue
  2. 13
      src/components/GiftedDialog.vue
  3. 26
      src/components/GiftedPrompts.vue
  4. 27
      src/components/MembersList.vue
  5. 21
      src/components/OnboardingDialog.vue
  6. 16
      src/components/UserNameDialog.vue
  7. 2
      src/constants/app.ts
  8. 36
      src/db/databaseUtil.ts
  9. 5
      src/libs/util.ts
  10. 2
      src/main.web.ts
  11. 5
      src/services/PlatformService.ts
  12. 5
      src/services/platforms/WebPlatformService.ts
  13. 7
      src/views/AccountViewView.vue
  14. 16
      src/views/ClaimCertificateView.vue
  15. 16
      src/views/ClaimReportCertificateView.vue
  16. 14
      src/views/ClaimView.vue
  17. 14
      src/views/ConfirmGiftView.vue
  18. 15
      src/views/ContactAmountsView.vue
  19. 40
      src/views/ContactEditView.vue
  20. 14
      src/views/ContactGiftingView.vue
  21. 32
      src/views/ContactImportView.vue
  22. 35
      src/views/ContactQRScanFullView.vue
  23. 53
      src/views/ContactQRScanShowView.vue
  24. 65
      src/views/ContactsView.vue

27
src/components/FeedFilters.vue

@ -99,8 +99,11 @@ import {
LTileLayer,
} from "@vue-leaflet/vue-leaflet";
import { Router } from "vue-router";
import { USE_DEXIE_DB } from "@/constants/app";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: {
@ -144,20 +147,36 @@ export default class FeedFilters extends Vue {
async toggleNearby() {
this.settingChanged = true;
this.isNearby = !this.isNearby;
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
`UPDATE settings SET filterFeedByNearby = ? WHERE id = ?`,
[this.isNearby, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedByNearby: this.isNearby,
});
}
}
async clearAll() {
if (this.hasVisibleDid || this.isNearby) {
this.settingChanged = true;
}
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
`UPDATE settings SET filterFeedByNearby = ? AND filterFeedByVisible = ? WHERE id = ?`,
[false, false, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedByNearby: false,
filterFeedByVisible: false,
});
}
this.hasVisibleDid = false;
this.isNearby = false;
@ -168,10 +187,18 @@ export default class FeedFilters extends Vue {
this.settingChanged = true;
}
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
`UPDATE settings SET filterFeedByNearby = ? AND filterFeedByVisible = ? WHERE id = ?`,
[true, true, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedByNearby: true,
filterFeedByVisible: true,
});
}
this.hasVisibleDid = true;
this.isNearby = true;

13
src/components/GiftedDialog.vue

@ -89,7 +89,7 @@
<script lang="ts">
import { Vue, Component, Prop } from "vue-facing-decorator";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
createAndSubmitGive,
didInfo,
@ -98,8 +98,10 @@ import {
import * as libsUtil from "../libs/util";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component
export default class GiftedDialog extends Vue {
@ -148,7 +150,16 @@ export default class GiftedDialog extends Vue {
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
const platformService = PlatformServiceFactory.getInstance();
const result = await platformService.dbQuery(`SELECT * FROM contacts`);
if (result) {
this.allContacts = databaseUtil.mapQueryResultToValues(
result,
) as unknown as Contact[];
}
if (USE_DEXIE_DB) {
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await retrieveAccountDids();

26
src/components/GiftedPrompts.vue

@ -74,10 +74,12 @@
import { Vue, Component } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, NotificationIface } from "../constants/app";
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db } from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { GiverReceiverInputInfo } from "../libs/util";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component
export default class GivenPrompts extends Vue {
@ -127,8 +129,16 @@ export default class GivenPrompts extends Vue {
this.visible = true;
this.callbackOnFullGiftInfo = callbackOnFullGiftInfo;
await db.open();
const platformService = PlatformServiceFactory.getInstance();
const result = await platformService.dbQuery(
"SELECT COUNT(*) FROM contacts",
);
if (result) {
this.numContacts = result.values[0][0] as number;
}
if (USE_DEXIE_DB) {
this.numContacts = await db.contacts.count();
}
this.shownContactDbIndices = new Array<boolean>(this.numContacts); // all undefined to start
}
@ -229,10 +239,22 @@ export default class GivenPrompts extends Vue {
this.nextIdeaPastContacts();
} else {
// get the contact at that offset
const platformService = PlatformServiceFactory.getInstance();
const result = await platformService.dbQuery(
"SELECT * FROM contacts LIMIT 1 OFFSET ?",
[someContactDbIndex],
);
if (result) {
this.currentContact = databaseUtil.mapQueryResultToValues(result)[
someContactDbIndex
] as unknown as Contact;
}
if (USE_DEXIE_DB) {
await db.open();
this.currentContact = await db.contacts
.offset(someContactDbIndex)
.first();
}
this.shownContactDbIndices[someContactDbIndex] = true;
}
}

27
src/components/MembersList.vue

@ -172,8 +172,10 @@ import {
} from "../libs/endorserServer";
import { decryptMessage } from "../libs/crypto";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import * as libsUtil from "../libs/util";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface Member {
admitted: boolean;
@ -355,8 +357,17 @@ export default class MembersList extends Vue {
}
async loadContacts() {
const platformService = PlatformServiceFactory.getInstance();
const result = await platformService.dbQuery("SELECT * FROM contacts");
if (result) {
this.contacts = databaseUtil.mapQueryResultToValues(
result,
) as unknown as Contact[];
}
if (USE_DEXIE_DB) {
this.contacts = await db.contacts.toArray();
}
}
getContactFor(did: string): Contact | undefined {
return this.contacts.find((contact) => contact.did === did);
@ -439,7 +450,14 @@ export default class MembersList extends Vue {
if (result.success) {
decrMember.isRegistered = true;
if (oldContact) {
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET registered = ? WHERE did = ?",
[true, decrMember.did],
);
if (USE_DEXIE_DB) {
await db.contacts.update(decrMember.did, { registered: true });
}
oldContact.registered = true;
}
this.$notify(
@ -492,7 +510,14 @@ export default class MembersList extends Vue {
name: member.name,
};
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"INSERT INTO contacts (did, name) VALUES (?, ?)",
[member.did, member.name],
);
if (USE_DEXIE_DB) {
await db.contacts.add(newContact);
}
this.contacts.push(newContact);
this.$notify(

21
src/components/OnboardingDialog.vue

@ -201,13 +201,16 @@
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
db,
retrieveSettingsForActiveAccount,
updateAccountSettings,
} from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { OnboardPage } from "../libs/util";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Contact } from "@/db/tables/contacts";
@Component({
computed: {
@ -222,7 +225,7 @@ export default class OnboardingDialog extends Vue {
$router!: Router;
activeDid = "";
firstContactName = null;
firstContactName = "";
givenName = "";
isRegistered = false;
numContacts = 0;
@ -234,10 +237,22 @@ export default class OnboardingDialog extends Vue {
const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
this.isRegistered = !!settings.isRegistered;
const platformService = PlatformServiceFactory.getInstance();
const dbContacts = await platformService.dbQuery("SELECT * FROM contacts");
if (dbContacts) {
this.numContacts = dbContacts.values.length;
const firstContact = dbContacts.values[0];
const fullContact = databaseUtil.mapColumnsToValues(dbContacts.columns, [
firstContact,
]) as unknown as Contact;
this.firstContactName = fullContact.name || "";
}
if (USE_DEXIE_DB) {
const contacts = await db.contacts.toArray();
this.numContacts = contacts.length;
if (this.numContacts > 0) {
this.firstContactName = contacts[0].name;
this.firstContactName = contacts[0].name || "";
}
}
this.visible = true;
if (this.page === OnboardPage.Create) {

16
src/components/UserNameDialog.vue

@ -37,9 +37,11 @@
<script lang="ts">
import { Vue, Component, Prop } from "vue-facing-decorator";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component
export default class UserNameDialog extends Vue {
@ -61,15 +63,25 @@ export default class UserNameDialog extends Vue {
*/
async open(aCallback?: (name?: string) => void) {
this.callback = aCallback || this.callback;
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.givenName = settings.firstName || "";
this.visible = true;
}
async onClickSaveChanges() {
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE settings SET firstName = ? WHERE key = ?",
[this.givenName, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
firstName: this.givenName,
});
}
this.visible = false;
this.callback(this.givenName);
}

2
src/constants/app.ts

@ -51,7 +51,7 @@ export const IMAGE_TYPE_PROFILE = "profile";
export const PASSKEYS_ENABLED =
!!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.

36
src/db/databaseUtil.ts

@ -2,6 +2,7 @@ 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";
import { QueryExecResult } from "@/interfaces/database";
export async function updateDefaultSettings(
settingsChanges: Settings,
@ -149,6 +150,26 @@ export async function logConsoleAndDb(
await logToDb(message);
}
/**
* Generates an SQL INSERT 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
* @returns Object containing the SQL statement and parameters array
*/
export function generateInsertStatement(
model: Record<string, unknown>,
tableName: string,
): { sql: string; params: unknown[] } {
const columns = Object.keys(model);
const values = Object.values(model);
const placeholders = values.map(() => "?").join(", ");
const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
return {
sql: insertSql,
params: values,
};
}
/**
* Generates an SQL UPDATE statement and parameters from a model object.
* @param model The model object containing fields to update
@ -157,7 +178,7 @@ export async function logConsoleAndDb(
* @param whereParams Parameters for the WHERE clause
* @returns Object containing the SQL statement and parameters array
*/
function generateUpdateStatement(
export function generateUpdateStatement(
model: Record<string, unknown>,
tableName: string,
whereClause: string,
@ -186,6 +207,17 @@ function generateUpdateStatement(
};
}
export function mapQueryResultToValues(
record: QueryExecResult | undefined,
): Array<Record<string, unknown>> {
if (!record) {
return [];
}
return mapColumnsToValues(record.columns, record.values) as Array<
Record<string, unknown>
>;
}
/**
* Maps an array of column names to an array of value arrays, creating objects where each column name
* is mapped to its corresponding value.
@ -196,7 +228,7 @@ function generateUpdateStatement(
export function mapColumnsToValues(
columns: string[],
values: unknown[][],
): Record<string, unknown>[] {
): Array<Record<string, unknown>> {
return values.map((row) => {
const obj: Record<string, unknown> = {};
columns.forEach((column, index) => {

5
src/libs/util.ts

@ -558,9 +558,8 @@ export const retrieveFullyDecryptedAccount = async (
) {
throw new Error("Account not found.");
}
const fullAccountData = databaseUtil.mapColumnsToValues(
dbAccount.columns,
dbAccount.values,
const fullAccountData = databaseUtil.mapQueryResultToValues(
dbAccount,
)[0] as AccountEncrypted;
const identityEncr = base64ToArrayBuffer(fullAccountData.identityEncrBase64);
const mnemonicEncr = base64ToArrayBuffer(fullAccountData.mnemonicEncrBase64);

2
src/main.web.ts

@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error but not sure why it's not in there
import { initBackend } from "absurd-sql/dist/indexeddb-main-thread";
import { initializeApp } from "./main.common";
import "./registerServiceWorker"; // Web PWA support

5
src/services/PlatformService.ts

@ -107,7 +107,10 @@ export interface PlatformService {
* @param params - The parameters to pass to the query
* @returns Promise resolving to the query result
*/
dbQuery(sql: string, params?: unknown[]): Promise<QueryExecResult>;
dbQuery(
sql: string,
params?: unknown[],
): Promise<QueryExecResult | undefined>;
/**
* Executes a create/update/delete on the database.

5
src/services/platforms/WebPlatformService.ts

@ -365,7 +365,10 @@ export class WebPlatformService implements PlatformService {
/**
* @see PlatformService.dbQuery
*/
dbQuery(sql: string, params?: unknown[]): Promise<QueryExecResult> {
dbQuery(
sql: string,
params?: unknown[],
): Promise<QueryExecResult | undefined> {
return databaseService.query(sql, params).then((result) => result[0]);
}

7
src/views/AccountViewView.vue

@ -1350,17 +1350,14 @@ export default class AccountViewView extends Vue {
* Processes the identity and updates the component's state.
*/
async processIdentity() {
let account: Account | undefined = undefined;
const platformService = PlatformServiceFactory.getInstance();
const dbAccount = await platformService.dbQuery(
"SELECT * FROM accounts WHERE did = ?",
[this.activeDid],
);
let account: Account | undefined = undefined;
if (dbAccount) {
account = databaseUtil.mapColumnsToValues(
dbAccount.columns,
dbAccount.values,
)[0] as Account;
account = databaseUtil.mapQueryResultToValues(dbAccount)[0] as Account;
}
if (USE_DEXIE_DB) {
account = await retrieveAccountMetadata(this.activeDid);

16
src/views/ClaimCertificateView.vue

@ -14,11 +14,14 @@
import { Component, Vue } from "vue-facing-decorator";
import { nextTick } from "vue";
import QRCode from "qrcode";
import { APP_SERVER, NotificationIface } from "../constants/app";
import { APP_SERVER, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import * as serverUtil from "../libs/endorserServer";
import { GenericCredWrapper, GenericVerifiableCredential } from "../interfaces";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Contact } from "@/db/tables/contacts";
@Component
export default class ClaimCertificateView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -84,8 +87,17 @@ export default class ClaimCertificateView extends Vue {
claimData: GenericCredWrapper<GenericVerifiableCredential>,
confirmerIds: Array<string>,
) {
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
let allContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
const allContacts = await db.contacts.toArray();
allContacts = await db.contacts.toArray();
}
const canvas = this.$refs.claimCanvas as HTMLCanvasElement;
if (canvas) {

16
src/views/ClaimReportCertificateView.vue

@ -11,10 +11,13 @@ import { Component, Vue } from "vue-facing-decorator";
import { nextTick } from "vue";
import QRCode from "qrcode";
import { APP_SERVER, NotificationIface } from "../constants/app";
import { APP_SERVER, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import * as endorserServer from "../libs/endorserServer";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Contact } from "@/db/tables/contacts";
@Component
export default class ClaimReportCertificateView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -66,8 +69,17 @@ export default class ClaimReportCertificateView extends Vue {
async drawCanvas(
claimData: endorserServer.GenericCredWrapper<endorserServer.GenericVerifiableCredential>,
) {
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
let allContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
const allContacts = await db.contacts.toArray();
allContacts = await db.contacts.toArray();
}
const canvas = this.$refs.claimCanvas as HTMLCanvasElement;
if (canvas) {

14
src/views/ClaimView.vue

@ -542,13 +542,14 @@ import { useClipboard } from "@vueuse/core";
import { GenericVerifiableCredential } from "../interfaces";
import GiftedDialog from "../components/GiftedDialog.vue";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
db,
logConsoleAndDb,
retrieveSettingsForActiveAccount,
} from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import * as serverUtil from "../libs/endorserServer";
import {
GenericCredWrapper,
@ -557,6 +558,7 @@ import {
} from "../interfaces";
import * as libsUtil from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: { GiftedDialog, QuickNav },
@ -624,7 +626,17 @@ export default class ClaimView extends Vue {
const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
this.isRegistered = settings.isRegistered || false;
try {

14
src/views/ConfirmGiftView.vue

@ -438,9 +438,10 @@ import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import * as serverUtil from "../libs/endorserServer";
import { GenericVerifiableCredential, GiveSummaryRecord } from "../interfaces";
import { displayAmount } from "../libs/endorserServer";
@ -448,6 +449,7 @@ import * as libsUtil from "../libs/util";
import { retrieveAccountDids } from "../libs/util";
import TopMessage from "../components/TopMessage.vue";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/**
* ConfirmGiftView Component
*
@ -531,7 +533,17 @@ export default class ConfirmGiftView extends Vue {
const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
this.isRegistered = settings.isRegistered || false;
this.allMyDids = await retrieveAccountDids();

15
src/views/ContactAmountsView.vue

@ -117,9 +117,10 @@ import { Component, Vue } from "vue-facing-decorator";
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import {
AgreeVerifiableCredential,
GiveSummaryRecord,
@ -133,6 +134,7 @@ import {
} from "../libs/endorserServer";
import { retrieveAccountCount } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({ components: { QuickNav } })
export default class ContactAmountssView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -154,7 +156,18 @@ export default class ContactAmountssView extends Vue {
async created() {
try {
const contactDid = this.$route.query["contactDid"] as string;
const platformService = PlatformServiceFactory.getInstance();
const dbContact = await platformService.dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[contactDid],
);
this.contact = databaseUtil.mapQueryResultToValues(
dbContact,
)[0] as unknown as Contact;
if (USE_DEXIE_DB) {
await db.open();
this.contact = (await db.contacts.get(contactDid)) || null;
}
const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings?.activeDid || "";

40
src/views/ContactEditView.vue

@ -138,9 +138,11 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { AppString, NotificationIface } from "../constants/app";
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db } from "../db/index";
import { Contact, ContactMethod } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/**
* Contact Edit View Component
@ -188,7 +190,7 @@ export default class ContactEditView extends Vue {
$router!: Router;
/** Current contact data */
contact: Contact = {
contact: Contact | undefined = {
did: "",
name: "",
notes: "",
@ -220,7 +222,21 @@ export default class ContactEditView extends Vue {
*/
async created() {
const contactDid = this.$route.params.did;
const contact = await db.contacts.get(contactDid || "");
const platformService = PlatformServiceFactory.getInstance();
const dbContact = await platformService.dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[contactDid],
);
let contact: Contact | undefined = databaseUtil.mapQueryResultToValues(
dbContact,
)[0] as unknown as Contact;
contact.contactMethods = JSON.parse(
(contact?.contactMethods as unknown as string) || "[]",
);
if (USE_DEXIE_DB) {
await db.open();
contact = await db.contacts.get(contactDid || "");
}
if (contact) {
this.contact = contact;
this.contactName = contact.name || "";
@ -322,12 +338,24 @@ export default class ContactEditView extends Vue {
}
// Save to database
await db.contacts.update(this.contact.did, {
const platformService = PlatformServiceFactory.getInstance();
const contactMethodsString = JSON.stringify(contactMethods);
await platformService.dbExec(
"UPDATE contacts SET name = ?, notes = ?, contactMethods = ? WHERE did = ?",
[
this.contactName,
this.contactNotes,
contactMethodsString,
this.contact?.did || "",
],
);
if (USE_DEXIE_DB) {
await db.contacts.update(this.contact?.did || "", {
name: this.contactName,
notes: this.contactNotes,
contactMethods: contactMethods,
});
}
// Notify success and redirect
this.$notify({
group: "alert",
@ -336,7 +364,7 @@ export default class ContactEditView extends Vue {
text: "The contact info has been updated successfully.",
});
(this.$router as Router).push({
path: "/did/" + encodeURIComponent(this.contact.did),
path: "/did/" + encodeURIComponent(this.contact?.did || ""),
});
}
}

14
src/views/ContactGiftingView.vue

@ -76,11 +76,13 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import GiftedDialog from "../components/GiftedDialog.vue";
import QuickNav from "../components/QuickNav.vue";
import EntityIcon from "../components/EntityIcon.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { GiverReceiverInputInfo } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: { GiftedDialog, QuickNav, EntityIcon },
})
@ -102,12 +104,22 @@ export default class ContactGiftingView extends Vue {
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts ORDER BY name",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
this.allContacts = baseContacts.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
);
}
this.projectId = (this.$route.query["projectId"] as string) || "";
this.prompt = (this.$route.query["prompt"] as string) ?? this.prompt;

32
src/views/ContactImportView.vue

@ -200,13 +200,19 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import EntityIcon from "../components/EntityIcon.vue";
import OfferDialog from "../components/OfferDialog.vue";
import { APP_SERVER, AppString, NotificationIface } from "../constants/app";
import {
APP_SERVER,
AppString,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import {
db,
logConsoleAndDb,
retrieveSettingsForActiveAccount,
} from "../db/index";
import { Contact, ContactMethod } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import * as libsUtil from "../libs/util";
import {
capitalizeAndInsertSpacesBeforeCaps,
@ -215,6 +221,7 @@ import {
} from "../libs/endorserServer";
import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { decodeEndorserJwt } from "../libs/crypto/vc";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/**
* Contact Import View Component
@ -401,8 +408,17 @@ export default class ContactImportView extends Vue {
this.contactsImporting = contacts;
this.contactsSelected = new Array(this.contactsImporting.length).fill(true);
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
let baseContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
const baseContacts = await db.contacts.toArray();
baseContacts = await db.contacts.toArray();
}
// Check for existing contacts and differences
for (let i = 0; i < this.contactsImporting.length; i++) {
@ -515,7 +531,19 @@ export default class ContactImportView extends Vue {
const contact = this.contactsImporting[i];
const existingContact = this.contactsExisting[contact.did];
if (existingContact) {
const platformService = PlatformServiceFactory.getInstance();
// @ts-expect-error because we're just using the value to store to the DB
contact.contactMethods = JSON.stringify(contact.contactMethods);
const { sql, params } = databaseUtil.generateUpdateStatement(
contact as unknown as Record<string, unknown>,
"contacts",
"did = ?",
[contact.did],
);
await platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
await db.contacts.update(contact.did, contact);
}
updatedCount++;
} else {
// without explicit clone on the Proxy, we get: DataCloneError: Failed to execute 'add' on 'IDBObjectStore': #<Object> could not be cloned.

35
src/views/ContactQRScanFullView.vue

@ -104,23 +104,26 @@
</template>
<script lang="ts">
import QRCodeVue3 from "qr-code-generator-vue3";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { logger } from "../utils/logger";
import { QRScannerFactory } from "../services/QRScanner/QRScannerFactory";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db } from "../db/index";
import { Contact } from "../db/tables/contacts";
import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { decodeEndorserJwt, ETHR_DID_PREFIX } from "../libs/crypto/vc";
import { retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { setVisibilityUtil } from "../libs/endorserServer";
import { useClipboard } from "@vueuse/core";
import QRCodeVue3 from "qr-code-generator-vue3";
import UserNameDialog from "../components/UserNameDialog.vue";
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
import { retrieveAccountMetadata } from "../libs/util";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface QRScanResult {
rawValue?: string;
@ -434,13 +437,22 @@ export default class ContactQRScan extends Vue {
async addNewContact(contact: Contact) {
try {
logger.info("Opening database connection for new contact");
await db.open();
// Check if contact already exists
const existingContacts = await db.contacts.toArray();
const existingContact = existingContacts.find(
(c) => c.did === contact.did,
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[contact.did],
);
const existingContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
let existingContact: Contact | undefined = existingContacts[0];
if (USE_DEXIE_DB) {
await db.open();
const existingContacts = await db.contacts.toArray();
existingContact = existingContacts.find((c) => c.did === contact.did);
}
if (existingContact) {
logger.info("Contact already exists", { did: contact.did });
@ -457,7 +469,16 @@ export default class ContactQRScan extends Vue {
}
// Add new contact
// @ts-expect-error because we're just using the value to store to the DB
contact.contactMethods = JSON.stringify(contact.contactMethods);
const { sql, params } = databaseUtil.generateInsertStatement(
contact as unknown as Record<string, unknown>,
"contacts",
);
await platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
await db.contacts.add(contact);
}
if (this.activeDid) {
logger.info("Setting contact visibility", { did: contact.did });

53
src/views/ContactQRScanShowView.vue

@ -190,10 +190,11 @@ import { QrcodeStream } from "vue-qrcode-reader";
import QuickNav from "../components/QuickNav.vue";
import UserNameDialog from "../components/UserNameDialog.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import { getContactJwtFromJwtUrl } from "../libs/crypto";
import {
generateEndorserJwtUrlForAccount,
@ -206,6 +207,7 @@ import { Router } from "vue-router";
import { logger } from "../utils/logger";
import { QRScannerFactory } from "@/services/QRScanner/QRScannerFactory";
import { CameraState } from "@/services/QRScanner/types";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface QRScanResult {
rawValue?: string;
@ -591,7 +593,14 @@ export default class ContactQRScanShow extends Vue {
);
if (regResult.success) {
contact.registered = true;
db.contacts.update(contact.did, { registered: true });
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET registered = ? WHERE did = ?",
[true, contact.did],
);
if (USE_DEXIE_DB) {
await db.contacts.update(contact.did, { registered: true });
}
logger.info("Contact registration successful", { did: contact.did });
this.$notify(
@ -759,13 +768,22 @@ export default class ContactQRScanShow extends Vue {
async addNewContact(contact: Contact) {
try {
logger.info("Opening database connection for new contact");
await db.open();
// Check if contact already exists
const existingContacts = await db.contacts.toArray();
const existingContact = existingContacts.find(
(c) => c.did === contact.did,
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[contact.did],
);
const existingContacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
let existingContact: Contact | undefined = existingContacts[0];
if (USE_DEXIE_DB) {
await db.open();
const existingContacts = await db.contacts.toArray();
existingContact = existingContacts.find((c) => c.did === contact.did);
}
if (existingContact) {
logger.info("Contact already exists", { did: contact.did });
@ -782,7 +800,16 @@ export default class ContactQRScanShow extends Vue {
}
// Add new contact
// @ts-expect-error because we're just using the value to store to the DB
contact.contactMethods = JSON.stringify(contact.contactMethods);
const { sql, params } = databaseUtil.generateInsertStatement(
contact as unknown as Record<string, unknown>,
"contacts",
);
await platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
await db.contacts.add(contact);
}
if (this.activeDid) {
logger.info("Setting contact visibility", { did: contact.did });
@ -816,17 +843,31 @@ export default class ContactQRScanShow extends Vue {
text: "Do you want to register them?",
onCancel: async (stopAsking?: boolean) => {
if (stopAsking) {
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE settings SET hideRegisterPromptOnNewContact = ? WHERE key = ?",
[stopAsking, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: stopAsking,
});
}
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onNo: async (stopAsking?: boolean) => {
if (stopAsking) {
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE settings SET hideRegisterPromptOnNewContact = ? WHERE key = ?",
[stopAsking, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: stopAsking,
});
}
this.hideRegisterPromptOnNewContact = stopAsking;
}
},

65
src/views/ContactsView.vue

@ -361,7 +361,12 @@ import GiftedDialog from "../components/GiftedDialog.vue";
import OfferDialog from "../components/OfferDialog.vue";
import ContactNameDialog from "../components/ContactNameDialog.vue";
import TopMessage from "../components/TopMessage.vue";
import { APP_SERVER, AppString, NotificationIface } from "../constants/app";
import {
APP_SERVER,
AppString,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import {
db,
logConsoleAndDb,
@ -370,6 +375,7 @@ import {
updateDefaultSettings,
} from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { decodeEndorserJwt } from "../libs/crypto/vc";
import {
@ -390,6 +396,7 @@ import {
import * as libsUtil from "../libs/util";
import { generateSaveAndActivateIdentity } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: {
GiftedDialog,
@ -438,8 +445,11 @@ export default class ContactsView extends Vue {
libsUtil = libsUtil;
public async created() {
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
await db.open();
const settings = await retrieveSettingsForActiveAccount();
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.isRegistered = !!settings.isRegistered;
@ -457,6 +467,15 @@ export default class ContactsView extends Vue {
this.loadGives();
}
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts ORDER BY name",
);
this.contacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
@ -464,6 +483,7 @@ export default class ContactsView extends Vue {
(a.name || "").localeCompare(b.name || ""),
);
}
}
private async processContactJwt() {
// handle a contact sent via URL
@ -820,12 +840,22 @@ export default class ContactsView extends Vue {
this.danger("An error occurred. Some contacts may have been added.");
}
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts ORDER BY name",
);
this.contacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
this.contacts = baseContacts.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
);
}
return;
}
@ -934,7 +964,15 @@ export default class ContactsView extends Vue {
seesMe,
registered,
};
return db.contacts.add(newContact);
const platformService = PlatformServiceFactory.getInstance();
const { sql, params } = databaseUtil.generateInsertStatement(
newContact as unknown as Record<string, unknown>,
"contacts",
);
await platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
await db.contacts.add(newContact);
}
}
private async addContact(newContact: Contact) {
@ -946,8 +984,18 @@ export default class ContactsView extends Vue {
this.danger("The DID must begin with 'did:'", "Invalid DID");
return;
}
return db.contacts
.add(newContact)
const platformService = PlatformServiceFactory.getInstance();
const { sql, params } = databaseUtil.generateInsertStatement(
newContact as unknown as Record<string, unknown>,
"contacts",
);
let contactPromise = platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
// @ts-expect-error since the result of this promise won't be used, and this will go away soon
contactPromise = db.contacts.add(newContact);
}
return contactPromise
.then(() => {
const allContacts = this.contacts.concat([newContact]);
this.contacts = R.sort(
@ -1063,7 +1111,14 @@ export default class ContactsView extends Vue {
);
if (regResult.success) {
contact.registered = true;
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET registered = ? WHERE did = ?",
[true, contact.did],
);
if (USE_DEXIE_DB) {
await db.contacts.update(contact.did, { registered: true });
}
this.$notify(
{

Loading…
Cancel
Save