@ -223,6 +223,75 @@ import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { decodeEndorserJwt } from "../libs/crypto/vc" ;
import { decodeEndorserJwt } from "../libs/crypto/vc" ;
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory" ;
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory" ;
/ * *
* Interface for contact data as stored in the database
* Differs from Contact interface in that contactMethods is stored as a JSON string
* /
interface ContactDbRecord {
did : string ;
contactMethods : string ;
name : string ;
notes : string ;
profileImageUrl : string ;
publicKeyBase64 : string ;
nextPubKeyHashB64 : string ;
seesMe : boolean ;
registered : boolean ;
}
/ * *
* Ensures a value is a string , never null or undefined
* /
function safeString ( val : unknown ) : string {
return typeof val === 'string' ? val : ( val == null ? '' : String ( val ) ) ;
}
/ * *
* Converts a Contact object to a ContactDbRecord for database storage
* @ param contact The contact object to convert
* @ returns A ContactDbRecord with contactMethods as a JSON string
* @ throws Error if contact . did is missing or invalid
* /
function contactToDbRecord ( contact : Contact ) : ContactDbRecord {
if ( ! contact . did ) {
throw new Error ( "Contact must have a DID" ) ;
}
/ / C o n v e r t c o n t a c t M e t h o d s a r r a y t o J S O N s t r i n g , d e f a u l t i n g t o e m p t y a r r a y
const contactMethodsStr = ( contact . contactMethods != null
? JSON . stringify ( contact . contactMethods )
: "[]" ) ;
return {
did : safeString ( contact . did ) , / / R e q u i r e d f i e l d , m u s t b e p r e s e n t
contactMethods : contactMethodsStr ,
name : safeString ( contact . name ) ,
notes : safeString ( contact . notes ) ,
profileImageUrl : safeString ( contact . profileImageUrl ) ,
publicKeyBase64 : safeString ( contact . publicKeyBase64 ) ,
nextPubKeyHashB64 : safeString ( contact . nextPubKeyHashB64 ) ,
seesMe : contact . seesMe ? ? false ,
registered : contact . registered ? ? false
} ;
}
/ * *
* Converts a ContactDbRecord back to a Contact object
* @ param record The database record to convert
* @ returns A Contact object with parsed contactMethods array
* /
function dbRecordToContact ( record : ContactDbRecord ) : Contact {
return {
... record ,
name : safeString ( record . name ) ,
notes : safeString ( record . notes ) ,
profileImageUrl : safeString ( record . profileImageUrl ) ,
publicKeyBase64 : safeString ( record . publicKeyBase64 ) ,
nextPubKeyHashB64 : safeString ( record . nextPubKeyHashB64 ) ,
contactMethods : JSON . parse ( record . contactMethods || "[]" )
} ;
}
/ * *
/ * *
* Contact Import View Component
* Contact Import View Component
* @ author Matthew Raymer
* @ author Matthew Raymer
@ -533,25 +602,36 @@ export default class ContactImportView extends Vue {
if ( this . contactsSelected [ i ] ) {
if ( this . contactsSelected [ i ] ) {
const contact = this . contactsImporting [ i ] ;
const contact = this . contactsImporting [ i ] ;
const existingContact = this . contactsExisting [ contact . did ] ;
const existingContact = this . contactsExisting [ contact . did ] ;
const platformService = PlatformServiceFactory . getInstance ( ) ;
/ / C o n v e r t c o n t a c t t o d a t a b a s e r e c o r d f o r m a t
const contactToStore = contactToDbRecord ( contact ) ;
if ( existingContact ) {
if ( existingContact ) {
const platformService = PlatformServiceFactory . getInstance ( ) ;
/ / U p d a t e e x i s t i n g c o n t a c t
/ / @ t s - e x p e c t - e r r o r b e c a u s e w e ' r e j u s t u s i n g t h e v a l u e t o s t o r e t o t h e D B
contact . contactMethods = JSON . stringify ( contact . contactMethods ) ;
const { sql , params } = databaseUtil . generateUpdateStatement (
const { sql , params } = databaseUtil . generateUpdateStatement (
contact as unknown as Record < string , unknown > ,
contactToStore as unknown as Record < string , unknown > ,
"contacts" ,
"contacts" ,
"did = ?" ,
"did = ?" ,
[ contact . did ] ,
[ contact . did ] ,
) ;
) ;
await platformService . dbExec ( sql , params ) ;
await platformService . dbExec ( sql , params ) ;
if ( USE_DEXIE_DB ) {
if ( USE_DEXIE_DB ) {
await db . contacts . update ( contact . did , contact ) ;
/ / F o r D e x i e , w e n e e d t o p a r s e t h e c o n t a c t M e t h o d s b a c k t o a n a r r a y
await db . contacts . update ( contact . did , dbRecordToContact ( contactToStore ) ) ;
}
}
updatedCount ++ ;
updatedCount ++ ;
} else {
} else {
/ / w i t h o u t e x p l i c i t c l o n e o n t h e P r o x y , w e g e t : D a t a C l o n e E r r o r : F a i l e d t o e x e c u t e ' a d d ' o n ' I D B O b j e c t S t o r e ' : # < O b j e c t > c o u l d n o t b e c l o n e d .
/ / A d d n e w c o n t a c t
/ / D a t a E r r o r : F a i l e d t o e x e c u t e ' a d d ' o n ' I D B O b j e c t S t o r e ' : E v a l u a t i n g t h e o b j e c t s t o r e ' s k e y p a t h y i e l d e d a v a l u e t h a t i s n o t a v a l i d k e y .
const { sql , params } = databaseUtil . generateInsertStatement (
await db . contacts . add ( R . clone ( contact ) ) ;
contactToStore as unknown as Record < string , unknown > ,
"contacts" ,
) ;
await platformService . dbExec ( sql , params ) ;
if ( USE_DEXIE_DB ) {
/ / F o r D e x i e , w e n e e d t o p a r s e t h e c o n t a c t M e t h o d s b a c k t o a n a r r a y
await db . contacts . add ( dbRecordToContact ( contactToStore ) ) ;
}
importedCount ++ ;
importedCount ++ ;
}
}
}
}