mirror of
https://github.com/status-im/status-protocol-go.git
synced 2025-03-04 04:20:38 +00:00
Move contacts to status-protocol-go & add delete chat endpoint
Adds to api calls, Contacts() not paginated and SaveContact() DeviceInfo and SystemTags have been stored as a blob to simplify querying, although at some point we might want to query system tags (for example to fetch all the blocked/added by us/added by them contacts), but not a use case for now.
This commit is contained in:
parent
b742356b68
commit
baa579640f
33
contact.go
Normal file
33
contact.go
Normal file
@ -0,0 +1,33 @@
|
||||
package statusproto
|
||||
|
||||
// ContactDeviceInfo is a struct containing information about a particular device owned by a contact
|
||||
type ContactDeviceInfo struct {
|
||||
// The installation id of the device
|
||||
InstallationID string `json:"id"`
|
||||
// Timestamp represents the last time we received this info
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
// FCMToken is to be used for push notifications
|
||||
FCMToken string `json:"fcmToken"`
|
||||
}
|
||||
|
||||
// Contact has information about a "Contact". A contact is not necessarily one
|
||||
// that we added or added us, that's based on SystemTags.
|
||||
type Contact struct {
|
||||
// ID of the contact
|
||||
ID string `json:"id"`
|
||||
// Ethereum address of the contact
|
||||
Address string `json:"address"`
|
||||
// Name of contact
|
||||
Name string `json:"name"`
|
||||
// Photo is the base64 encoded photo
|
||||
Photo string `json:"photoPath"`
|
||||
// LastUpdated is the last time we received an update from the contact
|
||||
// updates should be discarded if last updated is less than the one stored
|
||||
LastUpdated int64 `json:"lastUpdated"`
|
||||
// SystemTags contains information about whether we blocked/added/have been
|
||||
// added.
|
||||
SystemTags []string `json:"systemTags"`
|
||||
|
||||
DeviceInfo []ContactDeviceInfo `json:"deviceInfo"`
|
||||
TributeToTalk string `json:"tributeToTalk"`
|
||||
}
|
12
messenger.go
12
messenger.go
@ -391,6 +391,18 @@ func (m *Messenger) Chats(from, to int) ([]*Chat, error) {
|
||||
return m.persistence.Chats(from, to)
|
||||
}
|
||||
|
||||
func (m *Messenger) DeleteChat(chatID string, chatType ChatType) error {
|
||||
return m.persistence.DeleteChat(chatID, chatType)
|
||||
}
|
||||
|
||||
func (m *Messenger) SaveContact(contact Contact) error {
|
||||
return m.persistence.SaveContact(contact)
|
||||
}
|
||||
|
||||
func (m *Messenger) Contacts() ([]*Contact, error) {
|
||||
return m.persistence.Contacts()
|
||||
}
|
||||
|
||||
func (m *Messenger) Send(ctx context.Context, chat Chat, data []byte) ([]byte, error) {
|
||||
chatID := chat.ID
|
||||
if chatID == "" {
|
||||
|
@ -156,6 +156,33 @@ func (s *MessengerSuite) TestChatPersistencePublic() {
|
||||
s.Require().Equal(actualChat, expectedChat)
|
||||
}
|
||||
|
||||
func (s *MessengerSuite) TestDeleteChat() {
|
||||
chatID := "chatid"
|
||||
chat := Chat{
|
||||
ID: chatID,
|
||||
Name: "chat-name",
|
||||
Color: "#fffff",
|
||||
Active: true,
|
||||
ChatType: ChatTypePublic,
|
||||
Timestamp: 10,
|
||||
LastClockValue: 20,
|
||||
DeletedAtClockValue: 30,
|
||||
UnviewedMessagesCount: 40,
|
||||
LastMessageContentType: "something",
|
||||
LastMessageContent: "something-else",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.m.SaveChat(chat))
|
||||
savedChats, err := s.m.Chats(0, 10)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(savedChats))
|
||||
|
||||
s.Require().NoError(s.m.DeleteChat(chatID, ChatTypePublic))
|
||||
savedChats, err = s.m.Chats(0, 10)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(0, len(savedChats))
|
||||
}
|
||||
|
||||
func (s *MessengerSuite) TestChatPersistenceUpdate() {
|
||||
chat := Chat{
|
||||
ID: "chat-name",
|
||||
@ -321,6 +348,85 @@ func (s *MessengerSuite) TestChatPersistencePrivateGroupChat() {
|
||||
s.Require().Equal(expectedChat, actualChat)
|
||||
}
|
||||
|
||||
func (s *MessengerSuite) TestContactPersistence() {
|
||||
contact := Contact{
|
||||
ID: "contact-id",
|
||||
Address: "contact-address",
|
||||
Name: "contact-name",
|
||||
Photo: "contact-photo",
|
||||
LastUpdated: 20,
|
||||
SystemTags: []string{"1", "2"},
|
||||
DeviceInfo: []ContactDeviceInfo{
|
||||
ContactDeviceInfo{
|
||||
InstallationID: "1",
|
||||
Timestamp: 2,
|
||||
FCMToken: "token",
|
||||
},
|
||||
ContactDeviceInfo{
|
||||
InstallationID: "2",
|
||||
Timestamp: 3,
|
||||
FCMToken: "token-2",
|
||||
},
|
||||
},
|
||||
TributeToTalk: "talk",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.m.SaveContact(contact))
|
||||
savedContacts, err := s.m.Contacts()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(savedContacts))
|
||||
|
||||
actualContact := savedContacts[0]
|
||||
expectedContact := &contact
|
||||
|
||||
s.Require().Equal(expectedContact, actualContact)
|
||||
}
|
||||
|
||||
func (s *MessengerSuite) TestContactPersistenceUpdate() {
|
||||
contact := Contact{
|
||||
ID: "contact-id",
|
||||
Address: "contact-address",
|
||||
Name: "contact-name",
|
||||
Photo: "contact-photo",
|
||||
LastUpdated: 20,
|
||||
SystemTags: []string{"1", "2"},
|
||||
DeviceInfo: []ContactDeviceInfo{
|
||||
ContactDeviceInfo{
|
||||
InstallationID: "1",
|
||||
Timestamp: 2,
|
||||
FCMToken: "token",
|
||||
},
|
||||
ContactDeviceInfo{
|
||||
InstallationID: "2",
|
||||
Timestamp: 3,
|
||||
FCMToken: "token-2",
|
||||
},
|
||||
},
|
||||
TributeToTalk: "talk",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.m.SaveContact(contact))
|
||||
savedContacts, err := s.m.Contacts()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(savedContacts))
|
||||
|
||||
actualContact := savedContacts[0]
|
||||
expectedContact := &contact
|
||||
|
||||
s.Require().Equal(expectedContact, actualContact)
|
||||
|
||||
contact.Name = "updated-name"
|
||||
s.Require().NoError(s.m.SaveContact(contact))
|
||||
updatedContact, err := s.m.Contacts()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(updatedContact))
|
||||
|
||||
actualUpdatedContact := updatedContact[0]
|
||||
expectedUpdatedContact := &contact
|
||||
|
||||
s.Require().Equal(expectedUpdatedContact, actualUpdatedContact)
|
||||
}
|
||||
|
||||
func (s *MessengerSuite) TestSharedSecretHandler() {
|
||||
err := s.m.handleSharedSecrets(nil)
|
||||
s.NoError(err)
|
||||
|
@ -4,6 +4,8 @@
|
||||
// 000001_init.up.db.sql (840B)
|
||||
// 000002_add_chats.down.db.sql (74B)
|
||||
// 000002_add_chats.up.db.sql (541B)
|
||||
// 000003_add_contacts.down.db.sql (21B)
|
||||
// 000003_add_contacts.up.db.sql (251B)
|
||||
// doc.go (377B)
|
||||
|
||||
package migrations
|
||||
@ -128,7 +130,7 @@ func _000002_add_chatsDownDbSql() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000002_add_chats.down.db.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1564502835, 0)}
|
||||
info := bindataFileInfo{name: "000002_add_chats.down.db.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1564587343, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd3, 0xa7, 0xf0, 0x94, 0x7a, 0x9, 0xdc, 0x6c, 0x7b, 0xdc, 0x12, 0x30, 0x55, 0x31, 0x17, 0xf2, 0xcc, 0x6e, 0xfd, 0xbb, 0x70, 0xb9, 0xd8, 0x9f, 0x81, 0x83, 0xdc, 0x1d, 0x1c, 0x3a, 0x8d, 0xce}}
|
||||
return a, nil
|
||||
}
|
||||
@ -148,11 +150,51 @@ func _000002_add_chatsUpDbSql() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 541, mode: os.FileMode(0644), modTime: time.Unix(1564587096, 0)}
|
||||
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 541, mode: os.FileMode(0644), modTime: time.Unix(1564587387, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd, 0x7f, 0x3a, 0xd7, 0xf6, 0x8b, 0x6e, 0x4d, 0xce, 0x7d, 0x63, 0x1d, 0x30, 0xa2, 0xc1, 0xb, 0xa0, 0x35, 0x2e, 0xfa, 0xef, 0xf0, 0x39, 0xf7, 0x22, 0xdd, 0x31, 0x11, 0xb1, 0xff, 0xbf, 0xb3}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __000003_add_contactsDownDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x48\xce\xcf\x2b\x49\x4c\x2e\x29\xb6\xe6\x02\x04\x00\x00\xff\xff\x66\x64\xd9\xdd\x15\x00\x00\x00")
|
||||
|
||||
func _000003_add_contactsDownDbSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__000003_add_contactsDownDbSql,
|
||||
"000003_add_contacts.down.db.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _000003_add_contactsDownDbSql() (*asset, error) {
|
||||
bytes, err := _000003_add_contactsDownDbSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000003_add_contacts.down.db.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1564721146, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfc, 0x7e, 0xb, 0xec, 0x72, 0xcd, 0x21, 0x3e, 0xa2, 0x38, 0xe0, 0x95, 0x7e, 0xce, 0x4a, 0x17, 0xc8, 0xd0, 0x1c, 0xfa, 0xa3, 0x23, 0x5, 0xab, 0x89, 0xf9, 0xfc, 0x63, 0x7, 0x28, 0xe9, 0x93}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __000003_add_contactsUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\xcd\xc1\x4a\xc4\x30\x14\x85\xe1\x7d\x9e\xe2\x2c\x15\x5c\xb8\x77\x95\xc6\x3b\x50\x8c\xc9\x10\x32\xe0\xac\x42\x6c\xa2\x06\xa7\x4d\x69\x6e\x05\xdf\x5e\x8a\xa0\x0c\xdd\x7e\xe7\x87\xa3\x1c\x49\x4f\xf0\xb2\xd3\x84\xa1\x4e\x1c\x07\x6e\xb8\x11\x40\x49\xf0\xf4\xe2\x71\x74\xfd\xb3\x74\x67\x3c\xd1\x19\xd6\x40\x59\x73\xd0\xbd\xf2\x70\x74\xd4\x52\xd1\x9d\x00\x62\x4a\x4b\x6e\xed\xb7\x37\xd6\xc3\x9c\xb4\xde\x86\x29\x8e\x79\xaf\xf3\x47\xe5\xba\xe7\x4b\x6c\x1c\xd6\x39\x45\xce\x09\xbd\xf9\x1f\xf1\x48\x07\x79\xd2\x1e\xf7\x5b\xd6\xbe\x1b\xe7\x31\x70\x7c\x6f\xe8\xb4\xed\x36\x4b\xf9\xab\x0c\x39\x94\xe9\xad\xfe\x19\x2f\xe5\x75\xe5\x1c\xb8\x06\x8e\x97\xcf\xeb\x3f\x71\xfb\x20\x7e\x02\x00\x00\xff\xff\xc3\x2e\x5b\xed\xfb\x00\x00\x00")
|
||||
|
||||
func _000003_add_contactsUpDbSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__000003_add_contactsUpDbSql,
|
||||
"000003_add_contacts.up.db.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _000003_add_contactsUpDbSql() (*asset, error) {
|
||||
bytes, err := _000003_add_contactsUpDbSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000003_add_contacts.up.db.sql", size: 251, mode: os.FileMode(0644), modTime: time.Unix(1564721109, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8f, 0x19, 0x9f, 0x5c, 0x9d, 0xa1, 0xe5, 0x99, 0xbe, 0x47, 0xce, 0xa5, 0xd3, 0x51, 0x2f, 0x9b, 0x1d, 0xd9, 0x3f, 0x7a, 0xbf, 0xf, 0x76, 0x6b, 0x4f, 0x82, 0xbd, 0x13, 0x9d, 0x25, 0xdd, 0x60}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xbb\x6e\xc3\x30\x0c\x45\x77\x7f\xc5\x45\x96\x2c\xb5\xb4\x74\xea\xd6\xb1\x7b\x7f\x80\x91\x68\x89\x88\x1e\xae\x48\xe7\xf1\xf7\x85\xd3\x02\xcd\xd6\xf5\x00\xe7\xf0\xd2\x7b\x7c\x66\x51\x2c\x52\x18\xa2\x68\x1c\x58\x95\xc6\x1d\x27\x0e\xb4\x29\xe3\x90\xc4\xf2\x76\x72\xa1\x57\xaf\x46\xb6\xe9\x2c\xd5\x57\x49\x83\x8c\xfd\xe5\xf5\x30\x79\x8f\x40\xed\x68\xc8\xd4\x62\xe1\x47\x4b\xa1\x46\xc3\xa4\x25\x5c\xc5\x32\x08\xeb\xe0\x45\x6e\x0e\xef\x86\xc2\xa4\x06\xcb\x64\x47\x85\x65\x46\x20\xe5\x3d\xb3\xf4\x81\xd4\xe7\x93\xb4\x48\x46\x6e\x47\x1f\xcb\x13\xd9\x17\x06\x2a\x85\x23\x96\xd1\xeb\xc3\x55\xaa\x8c\x28\x83\x83\xf5\x71\x7f\x01\xa9\xb2\xa1\x51\x65\xdd\xfd\x4c\x17\x46\xeb\xbf\xe7\x41\x2d\xfe\xff\x11\xae\x7d\x9c\x15\xa4\xe0\xdb\xca\xc1\x38\xba\x69\x5a\x29\x9c\x29\x31\xf4\xab\x88\xf1\x34\x79\x9f\xfa\x5b\xe2\xc6\xbb\xf5\xbc\x71\x5e\xcf\x09\x3f\x35\xe9\x4d\x31\x77\x38\xe7\xff\x80\x4b\x1d\x6e\xfa\x0e\x00\x00\xff\xff\x9d\x60\x3d\x88\x79\x01\x00\x00")
|
||||
|
||||
func docGoBytes() ([]byte, error) {
|
||||
@ -272,6 +314,10 @@ var _bindata = map[string]func() (*asset, error){
|
||||
|
||||
"000002_add_chats.up.db.sql": _000002_add_chatsUpDbSql,
|
||||
|
||||
"000003_add_contacts.down.db.sql": _000003_add_contactsDownDbSql,
|
||||
|
||||
"000003_add_contacts.up.db.sql": _000003_add_contactsUpDbSql,
|
||||
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
@ -316,11 +362,13 @@ type bintree struct {
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"000001_init.down.db.sql": &bintree{_000001_initDownDbSql, map[string]*bintree{}},
|
||||
"000001_init.up.db.sql": &bintree{_000001_initUpDbSql, map[string]*bintree{}},
|
||||
"000002_add_chats.down.db.sql": &bintree{_000002_add_chatsDownDbSql, map[string]*bintree{}},
|
||||
"000002_add_chats.up.db.sql": &bintree{_000002_add_chatsUpDbSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
"000001_init.down.db.sql": &bintree{_000001_initDownDbSql, map[string]*bintree{}},
|
||||
"000001_init.up.db.sql": &bintree{_000001_initUpDbSql, map[string]*bintree{}},
|
||||
"000002_add_chats.down.db.sql": &bintree{_000002_add_chatsDownDbSql, map[string]*bintree{}},
|
||||
"000002_add_chats.up.db.sql": &bintree{_000002_add_chatsUpDbSql, map[string]*bintree{}},
|
||||
"000003_add_contacts.down.db.sql": &bintree{_000003_add_contactsDownDbSql, map[string]*bintree{}},
|
||||
"000003_add_contacts.up.db.sql": &bintree{_000003_add_contactsUpDbSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
|
1
migrations/sqlite/000003_add_contacts.down.db.sql
Normal file
1
migrations/sqlite/000003_add_contacts.down.db.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE contacts;
|
10
migrations/sqlite/000003_add_contacts.up.db.sql
Normal file
10
migrations/sqlite/000003_add_contacts.up.db.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE contacts (
|
||||
id TEXT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
address TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
photo TEXT NOT NULL,
|
||||
last_updated INT NOT NULL DEFAULT 0,
|
||||
system_tags BLOB,
|
||||
device_info BLOB,
|
||||
tribute_to_talk TEXT NOT NULL
|
||||
);
|
114
persistence.go
114
persistence.go
@ -97,10 +97,14 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
return
|
||||
}
|
||||
|
||||
func formatChatID(chatID string, chatType ChatType) string {
|
||||
return fmt.Sprintf("%s-%d", chatID, chatType)
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) SaveChat(chat Chat) error {
|
||||
var err error
|
||||
// We build the db chatID using the type, so that we have no clashes
|
||||
chatID := fmt.Sprintf("%s-%d", chat.ID, chat.ChatType)
|
||||
chatID := formatChatID(chat.ID, chat.ChatType)
|
||||
|
||||
pkey := []byte{}
|
||||
// For one to one chatID is an encoded public key
|
||||
@ -164,6 +168,12 @@ func (db sqlitePersistence) SaveChat(chat Chat) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) DeleteChat(chatID string, chatType ChatType) error {
|
||||
dbChatID := formatChatID(chatID, chatType)
|
||||
_, err := db.db.Exec("DELETE FROM chats WHERE id = ?", dbChatID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) Chats(from, to int) ([]*Chat, error) {
|
||||
|
||||
rows, err := db.db.Query(`SELECT
|
||||
@ -242,6 +252,108 @@ func (db sqlitePersistence) Chats(from, to int) ([]*Chat, error) {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) Contacts() ([]*Contact, error) {
|
||||
rows, err := db.db.Query(`SELECT
|
||||
id,
|
||||
address,
|
||||
name,
|
||||
photo,
|
||||
last_updated,
|
||||
system_tags,
|
||||
device_info,
|
||||
tribute_to_talk
|
||||
FROM contacts`)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var response []*Contact
|
||||
|
||||
for rows.Next() {
|
||||
contact := &Contact{}
|
||||
encodedDeviceInfo := []byte{}
|
||||
encodedSystemTags := []byte{}
|
||||
err := rows.Scan(
|
||||
&contact.ID,
|
||||
&contact.Address,
|
||||
&contact.Name,
|
||||
&contact.Photo,
|
||||
&contact.LastUpdated,
|
||||
&encodedSystemTags,
|
||||
&encodedDeviceInfo,
|
||||
&contact.TributeToTalk,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Restore device info
|
||||
deviceInfoDecoder := gob.NewDecoder(bytes.NewBuffer(encodedDeviceInfo))
|
||||
if err := deviceInfoDecoder.Decode(&contact.DeviceInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Restore system tags
|
||||
systemTagsDecoder := gob.NewDecoder(bytes.NewBuffer(encodedSystemTags))
|
||||
if err := systemTagsDecoder.Decode(&contact.SystemTags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response = append(response, contact)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) SaveContact(contact Contact) error {
|
||||
// Encode device info
|
||||
var encodedDeviceInfo bytes.Buffer
|
||||
deviceInfoEncoder := gob.NewEncoder(&encodedDeviceInfo)
|
||||
|
||||
if err := deviceInfoEncoder.Encode(contact.DeviceInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Encoded system tags
|
||||
var encodedSystemTags bytes.Buffer
|
||||
systemTagsEncoder := gob.NewEncoder(&encodedSystemTags)
|
||||
|
||||
if err := systemTagsEncoder.Encode(contact.SystemTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert record
|
||||
stmt, err := db.db.Prepare(`INSERT INTO contacts(
|
||||
id,
|
||||
address,
|
||||
name,
|
||||
photo,
|
||||
last_updated,
|
||||
system_tags,
|
||||
device_info,
|
||||
tribute_to_talk
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec(
|
||||
contact.ID,
|
||||
contact.Address,
|
||||
contact.Name,
|
||||
contact.Photo,
|
||||
contact.LastUpdated,
|
||||
encodedSystemTags.Bytes(),
|
||||
encodedDeviceInfo.Bytes(),
|
||||
contact.TributeToTalk,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// Messages returns messages for a given contact, in a given period. Ordered by a timestamp.
|
||||
func (db sqlitePersistence) Messages(chatID string, from, to time.Time) (result []*protocol.Message, err error) {
|
||||
rows, err := db.db.Query(`SELECT
|
||||
|
Loading…
x
Reference in New Issue
Block a user