Move contacts to status-go

Contacts are now in status-go, no migration of contacts is provided so
all contacts will be lost upon installing this build.

I have left the initialization of filters a bit sketchy (we wait that
load-filters is called twice), as the next step will be to avoid calling
load-filters altogether, as now that both contacts & chats are in
status-go, there's no reason to call it from status-react, and can be
called directly from status-go on loading.

Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrea Maria Piana 2019-08-03 15:01:17 +02:00
parent 68da6159ed
commit fe9d4e9cd8
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
13 changed files with 292 additions and 216 deletions

View File

@ -82,14 +82,15 @@
(navigation/navigate-back)))))
(fx/defn unblock-contact
[{:keys [db now]} public-key]
[{:keys [db now] :as cofx} public-key]
(let [contact (-> (get-in db [:contacts/contacts public-key])
(assoc :last-updated now)
(update :system-tags disj :contact/blocked))]
{:db (-> db
(update :contacts/blocked disj public-key)
(assoc-in [:contacts/contacts public-key] contact))
:data-store/tx [(contacts-store/save-contact-tx contact)]}))
(fx/merge cofx
{:db (-> db
(update :contacts/blocked disj public-key)
(assoc-in [:contacts/contacts public-key] contact))}
(contacts-store/save-contact-tx contact))))
(fx/defn block-contact-confirmation
[cofx public-key]

View File

@ -1,29 +1,38 @@
(ns status-im.contact.core
(:require [status-im.multiaccounts.model :as multiaccounts.model]
[status-im.transport.filters.core :as transport.filters]
[status-im.contact.db :as contact.db]
[status-im.contact.device-info :as device-info]
[status-im.ethereum.core :as ethereum]
[status-im.data-store.contacts :as contacts-store]
[status-im.mailserver.core :as mailserver]
[status-im.transport.message.contact :as message.contact]
[status-im.transport.message.protocol :as protocol]
[status-im.tribute-to-talk.db :as tribute-to-talk]
[status-im.tribute-to-talk.whitelist :as whitelist]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config]
[status-im.utils.fx :as fx]))
(:require
[re-frame.core :as re-frame]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.transport.filters.core :as transport.filters]
[status-im.contact.db :as contact.db]
[status-im.contact.device-info :as device-info]
[status-im.ethereum.core :as ethereum]
[status-im.data-store.contacts :as contacts-store]
[status-im.mailserver.core :as mailserver]
[status-im.transport.message.contact :as message.contact]
[status-im.transport.message.protocol :as protocol]
[status-im.tribute-to-talk.db :as tribute-to-talk]
[status-im.tribute-to-talk.whitelist :as whitelist]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config]
[status-im.utils.fx :as fx]))
(fx/defn load-contacts
[{:keys [db all-contacts]}]
{:events [::contacts-loaded]}
[{:keys [db] :as cofx} all-contacts]
(let [contacts-list (map #(vector (:public-key %) %) all-contacts)
contacts (into {} contacts-list)
tr-to-talk-enabled? (-> db tribute-to-talk/get-settings tribute-to-talk/enabled?)]
{:db (cond-> (-> db
(update :contacts/contacts #(merge contacts %))
(assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts)))
tr-to-talk-enabled?
(assoc :contacts/whitelist (whitelist/get-contact-whitelist all-contacts)))}))
(fx/merge cofx
{:db (cond-> (-> db
(update :contacts/contacts #(merge contacts %))
(assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts)))
tr-to-talk-enabled?
(assoc :contacts/whitelist (whitelist/get-contact-whitelist all-contacts)))}
;; TODO: This is currently called twice, once we load chats & when we load filters.
;; For now leaving as it is as the next step is not to have this being called from status-react
;; as both contacts & chats are in status-go, but we still need to signals the filters to
;; status-react for mailsevers/gaps, so will address separately
(transport.filters/load-filters))))
(defn build-contact
[{{:keys [chats multiaccount]
@ -47,9 +56,9 @@
{:keys [public-key] :as contact}]
(fx/merge cofx
{:db (-> db
(update-in [:contacts/contacts public-key] merge contact))
:data-store/tx [(contacts-store/save-contact-tx contact)]}
(transport.filters/load-contact contact)))
(update-in [:contacts/contacts public-key] merge contact))}
(transport.filters/load-contact contact)
(contacts-store/save-contact-tx contact)))
(fx/defn send-contact-request
[{:keys [db] :as cofx} {:keys [public-key] :as contact}]
@ -123,6 +132,9 @@
(def receive-contact-request-confirmation handle-contact-update)
(def receive-contact-update handle-contact-update)
(fx/defn initialize-contacts [cofx]
(contacts-store/fetch-contacts-rpc #(re-frame/dispatch [::contacts-loaded %])))
(fx/defn open-contact-toggle-list
[{:keys [db :as cofx]}]
(fx/merge cofx

View File

@ -6,48 +6,64 @@
[taoensso.timbre :as log]
[status-im.data-store.realm.core :as core]))
(defn- deserialize-contact [contact]
(defn deserialize-device-info [contact]
(update contact :deviceInfo (fn [device-info]
(reduce (fn [acc info]
(assoc acc
(:installationId info)
(clojure.set/rename-keys info {:fcmToken :fcm-token :installationId :id})))
{}
device-info))))
(defn serialize-device-info [contact]
(update contact :device-info (fn [device-info]
(map
#(clojure.set/rename-keys % {:fcm-token :fcmToken :id :installationId})
(vals device-info)))))
(defn <-rpc [contact]
(-> contact
(update :tags #(into #{} %))
(update :tribute-to-talk core/deserialize)
(update :system-tags
deserialize-device-info
(update :tributeToTalk core/deserialize)
(update :systemTags
#(reduce (fn [acc s]
(conj acc (keyword (subs s 1))))
#{}
%))))
%)) (clojure.set/rename-keys {:id :public-key
:photoPath :photo-path
:deviceInfo :device-info
:tributeToTalk :tribute-to-talk
:systemTags :system-tags
:lastUpdated :last-updated})))
(defn- serialize-contact [contact]
(defn ->rpc [contact]
(-> contact
(update :device-info #(or (vals %) []))
serialize-device-info
(update :tribute-to-talk core/serialize)
(update :system-tags #(mapv str %))
(update :tribute-to-talk core/serialize)))
(clojure.set/rename-keys {:public-key :id
:photo-path :photoPath
:device-info :deviceInfo
:tribute-to-talk :tributeToTalk
:system-tags :systemTags
:last-updated :lastUpdated})))
(re-frame/reg-cofx
:data-store/get-all-contacts
(fn [coeffects _]
(assoc coeffects :all-contacts (map deserialize-contact
(-> @core/account-realm
(core/get-all :contact)
(core/all-clj :contact))))))
(defn save-contact-rpc [{:keys [public-key] :as contact}]
(json-rpc/call {:method "shhext_saveContact"
:params [(->rpc contact)]
:on-success #(log/debug "saved contact" public-key "successfuly")
:on-failure #(log/error "failed to save contact" public-key %)}))
(defn fetch-contacts-rpc [on-success]
(json-rpc/call {:method "shhext_contacts"
:params []
:on-success #(on-success (map <-rpc %))
:on-failure #(log/error "failed to fetch contacts" %)}))
(defn save-contact-tx
"Returns tx function for saving contact"
[{:keys [public-key] :as contact}]
(fn [realm]
(core/create realm
:contact
(serialize-contact contact)
true)))
(defn save-contacts-tx
"Returns tx function for saving contacts"
[contacts]
(fn [realm]
(doseq [contact contacts]
((save-contact-tx contact) realm))))
(defn- get-contact-by-id [public-key realm]
(.objectForPrimaryKey realm "contact" public-key))
(save-contact-rpc contact))
(defn- get-messages-by-messages-ids
[message-ids]
@ -56,26 +72,13 @@
(.objects "message")
(.filtered (str "(" (core/in-query "message-id" message-ids) ")")))))
(defn- get-chat
[public-key]
(core/single
(core/get-by-field @core/account-realm
:chat
:chat-id
public-key)))
(defn block-user-tx
"Returns tx function for deleting user messages"
[{:keys [public-key] :as contact} messages-ids]
(fn [realm]
(core/create realm :contact (serialize-contact contact) true)
(data-store.chats/delete-chat-rpc public-key data-store.chats/one-to-one-chat-type)
(save-contact-rpc contact)
(when-let [user-messages
(get-messages-by-messages-ids messages-ids)]
(core/delete realm user-messages))
(data-store.chats/delete-chat-rpc public-key data-store.chats/one-to-one-chat-type)))
(core/delete realm user-messages))))
(defn delete-contact-tx
"Returns tx function for deleting contact"
[public-key]
(fn [realm]
(core/delete realm (get-contact-by-id public-key realm))))

View File

@ -130,7 +130,6 @@
(handlers/register-handler-fx
:init.callback/multiaccount-change-success
[(re-frame/inject-cofx :web3/get-web3)
(re-frame/inject-cofx :data-store/get-all-contacts)
(re-frame/inject-cofx :data-store/get-all-installations)
(re-frame/inject-cofx :data-store/all-chat-requests-ranges)]
multiaccount-change-success)

View File

@ -236,7 +236,6 @@
(fx/merge cofx
{:notifications/get-fcm-token nil}
(initialize-multiaccount-db address)
(contact/load-contacts)
#(when (dev-mode? %)
(models.dev-server/start))
(extensions.module/initialize)

View File

@ -6,6 +6,7 @@
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ethereum.subscriptions :as ethereum.subscriptions]
[status-im.chat.models.loading :as chat.loading]
[status-im.contact.core :as contact]
[status-im.ethereum.transactions.core :as transactions]
[status-im.fleet.core :as fleet]
[status-im.i18n :as i18n]
@ -209,6 +210,7 @@
(mobile-network/on-network-status-change)
(protocol/initialize-protocol)
(chat.loading/initialize-chats {:to -1})
(contact/initialize-contacts)
(universal-links/process-stored-event)
(chaos-mode/check-chaos-mode)
(finish-keycard-setup)

View File

@ -206,10 +206,11 @@
:topic topic})
(fx/defn set-filters-initialized [{:keys [db]}]
{:db (assoc db :filters/initialized true)})
{:db (update db :filters/initialized inc)})
;; We check that both chats & contacts have been initialized
(defn filters-initialized? [db]
(:filters/initialized db))
(>= (:filters/initialized db) 2))
(fx/defn handle-filters-added
"Called every time we load a filter from statusgo, either from explicit call

View File

@ -35,8 +35,8 @@
(update :system-tags conj tag))]
(fx/merge cofx
{:db (-> db
(assoc-in [:contacts/contacts public-key] contact))
:data-store/tx [(contacts-store/save-contact-tx contact)]}
(assoc-in [:contacts/contacts public-key] contact))}
(contacts-store/save-contact-tx contact)
(add-to-whitelist public-key))))
(fx/defn mark-tribute-paid

View File

@ -0,0 +1,68 @@
(ns status-im.test.data-store.contacts
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.data-store.contacts :as c]))
(deftest contact->rpc
(let [contact {:public-key "pk"
:address "address"
:name "name"
:photo-path "photo-path"
:tribute-to-talk "tribute-to-talk"
:device-info {"1" {:id "1"
:timestamp 1
:fcm-token "1"}
"2" {:id "2"
:timestamp 2
:fcm-token 3}}
:last-updated 1
:system-tags #{:a :b}}
expected-contact {:id "pk"
:address "address"
:name "name"
:photoPath "photo-path"
:tributeToTalk "[\"~#'\",\"tribute-to-talk\"]"
:deviceInfo [{:installationId "1"
:timestamp 1
:fcmToken "1"}
{:installationId "2"
:timestamp 2
:fcmToken 3}]
:lastUpdated 1
:systemTags #{":a" ":b"}}]
(testing "->rpc"
(is (= expected-contact (update
(c/->rpc contact)
:systemTags
#(into #{} %)))))))
(deftest contact<-rpc
(let [contact {:id "pk"
:address "address"
:name "name"
:photoPath "photo-path"
:tributeToTalk "[\"~#'\",\"tribute-to-talk\"]"
:deviceInfo [{:installationId "1"
:timestamp 1
:fcmToken "1"}
{:installationId "2"
:timestamp 2
:fcmToken 3}]
:lastUpdated 1
:systemTags [":a" ":b"]}
expected-contact {:public-key "pk"
:address "address"
:name "name"
:photo-path "photo-path"
:tribute-to-talk "tribute-to-talk"
:device-info {"1" {:id "1"
:timestamp 1
:fcm-token "1"}
"2" {:id "2"
:timestamp 2
:fcm-token 3}}
:last-updated 1
:system-tags #{:a :b}}]
(testing "<-rpc"
(is (= expected-contact (c/<-rpc contact))))))

View File

@ -1,149 +1,145 @@
(ns status-im.test.models.contact
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.contact.core :as model]))
(def public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917")
(def address "71adb0644e2b590e37dafdfea8bd58f0c7668c7f")
(deftest handle-contact-update-test
(testing "the contact is not in contacts"
(let [actual (model/handle-contact-update
public-key
1
{:name "name"
:profile-image "image"
:address "address"
:device-info [{:id "1"
:fcm-token "token-1"}]
:fcm-token "token"}
{:db {}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it stores the contact in the database"
(is (:data-store/tx actual)))
(testing "it adds a new contact"
(is (= {:public-key public-key
:photo-path "image"
:name "name"
:last-updated 1000
:system-tags #{:contact/request-received}
:device-info {"1" {:id "1"
:timestamp 1
:fcm-token "token-1"}}
:fcm-token "token"
:address "address"}
contact)))))
(testing "the contact is already in contacts"
(testing "timestamp is greater than last-updated"
(with-redefs [json-rpc/call (constantly nil)]
(testing "the contact is not in contacts"
(let [actual (model/handle-contact-update
public-key
1
{:name "name"
:profile-image "image"
:address "address"
:device-info [{:id "1"
:fcm-token "token-1"}]
:fcm-token "token"}
{:db {}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it adds a new contact"
(is (= {:public-key public-key
:photo-path "image"
:name "name"
:last-updated 1000
:system-tags #{:contact/request-received}
:device-info {"1" {:id "1"
:timestamp 1
:fcm-token "token-1"}}
:fcm-token "token"
:address "address"}
contact)))))
(testing "the contact is already in contacts"
(testing "timestamp is greater than last-updated"
(let [actual (model/handle-contact-update
public-key
1
{:name "new-name"
:profile-image "new-image"
:device-info [{:id "2"
:fcm-token "token-2"}
{:id "3"
:fcm-token "token-3"}]
:address "new-address"
:fcm-token "new-token"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:name "old-name"
:last-updated 0
:device-info {"1" {:id "1"
:timestamp 0
:fcm-token "token-1"}
"2" {:id "2"
:timestamp 0
:fcm-token "token-2"}}
:system-tags #{:contact/added}
:fcm-token "old-token"
:address "old-address"}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it updates the contact and adds contact/request-received to system tags"
(is (= {:public-key public-key
:photo-path "new-image"
:name "new-name"
:last-updated 1000
:device-info {"1" {:id "1"
:fcm-token "token-1"
:timestamp 0}
"2" {:id "2"
:fcm-token "token-2"
:timestamp 1}
"3" {:id "3"
:fcm-token "token-3"
:timestamp 1}}
:system-tags #{:contact/added :contact/request-received}
:fcm-token "new-token"
:address "new-address"}
contact)))))
(testing "timestamp is equal to last-updated"
(let [actual (model/handle-contact-update
public-key
1
{:name "new-name"
:profile-image "new-image"
:address "new-address"
:fcm-token "new-token"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:name "old-name"
:last-updated 1000
:system-tags #{:contact/added}
:fcm-token "old-token"
:address "old-address"}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it does nothing"
(is (nil? actual)))))
(testing "timestamp is less than last-updated"
(let [actual (model/handle-contact-update
public-key
0
{:name "new-name"
:profile-image "new-image"
:address "new-address"
:fcm-token "new-token"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:name "old-name"
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:fcm-token "old-token"
:address "old-address"}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it does nothing"
(is (nil? actual))))))
(testing "backward compatibility"
(let [actual (model/handle-contact-update
public-key
1
{:name "new-name"
:profile-image "new-image"
:device-info [{:id "2"
:fcm-token "token-2"}
{:id "3"
:fcm-token "token-3"}]
:address "new-address"
:fcm-token "new-token"}
:profile-image "new-image"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:device-info {"1" {:id "1"
:fcm-token "token-1"}}
:name "old-name"
:last-updated 0
:device-info {"1" {:id "1"
:timestamp 0
:fcm-token "token-1"}
"2" {:id "2"
:timestamp 0
:fcm-token "token-2"}}
:system-tags #{:contact/added}
:fcm-token "old-token"
:address "old-address"}}}})
:system-tags #{:contact/added}}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it stores the contact in the database"
(is (:data-store/tx actual)))
(testing "it updates the contact and adds contact/request-received to system tags"
(testing "it updates the contact"
(is (= {:public-key public-key
:photo-path "new-image"
:name "new-name"
:last-updated 1000
:device-info {"1" {:id "1"
:fcm-token "token-1"
:timestamp 0}
"2" {:id "2"
:fcm-token "token-2"
:timestamp 1}
"3" {:id "3"
:fcm-token "token-3"
:timestamp 1}}
:fcm-token "token-1"}}
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:fcm-token "new-token"
:address "new-address"}
contact)))))
(testing "timestamp is equal to last-updated"
(let [actual (model/handle-contact-update
public-key
1
{:name "new-name"
:profile-image "new-image"
:address "new-address"
:fcm-token "new-token"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:name "old-name"
:last-updated 1000
:system-tags #{:contact/added}
:fcm-token "old-token"
:address "old-address"}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it does nothing"
(is (nil? actual)))))
(testing "timestamp is less than last-updated"
(let [actual (model/handle-contact-update
public-key
0
{:name "new-name"
:profile-image "new-image"
:address "new-address"
:fcm-token "new-token"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:name "old-name"
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:fcm-token "old-token"
:address "old-address"}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it does nothing"
(is (nil? actual))))))
(testing "backward compatibility"
(let [actual (model/handle-contact-update
public-key
1
{:name "new-name"
:profile-image "new-image"}
{:db {:contacts/contacts
{public-key {:public-key public-key
:photo-path "old-image"
:device-info {"1" {:id "1"
:fcm-token "token-1"}}
:name "old-name"
:last-updated 0
:system-tags #{:contact/added}}}}})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it stores the contact in the database"
(is (:data-store/tx actual)))
(testing "it updates the contact"
(is (= {:public-key public-key
:photo-path "new-image"
:name "new-name"
:device-info {"1" {:id "1"
:fcm-token "token-1"}}
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:address address} contact)))))
(testing "the message is coming from us"
(testing "it does not update contacts"
(is (nil? (model/handle-contact-update "me" 1 {} {:db {:multiaccount {:public-key "me"}}}))))))
:address address} contact)))))
(testing "the message is coming from us"
(testing "it does not update contacts"
(is (nil? (model/handle-contact-update "me" 1 {} {:db {:multiaccount {:public-key "me"}}})))))))

View File

@ -16,6 +16,7 @@
[status-im.test.contact-recovery.core]
[status-im.test.contacts.device-info]
[status-im.test.data-store.chats]
[status-im.test.data-store.contacts]
[status-im.test.data-store.core]
[status-im.test.data-store.realm.core]
[status-im.test.ethereum.abi-spec]
@ -100,6 +101,7 @@
'status-im.test.contacts.db
'status-im.test.contacts.device-info
'status-im.test.data-store.chats
'status-im.test.data-store.contacts
'status-im.test.data-store.core
'status-im.test.data-store.realm.core
'status-im.test.ethereum.abi-spec

View File

@ -37,7 +37,6 @@
:multiaccounts/multiaccounts data/multiaccounts}
cofx {:db db
:web3 :web3
:all-contacts data/all-contacts
:all-installations []}
efx (events/multiaccount-change-success cofx [nil "address"])
new-db (:db efx)]
@ -50,9 +49,7 @@
(testing "Navigate to :home."
(is (= [:home nil] (efx :status-im.ui.screens.navigation/navigate-to))))
(testing "Multiaccount selected."
(is (contains? new-db :multiaccount)))
(testing "Contacts initialized."
(is (= 2 (count (:contacts/contacts new-db))))))))
(is (contains? new-db :multiaccount))))))
(deftest decryption-failure-on-multiaccount-change
(testing ":init.callback/multiaccount-change-error event received."

View File

@ -51,9 +51,7 @@
(testing "contact was tagged as tribute paid"
(is (= (get-in result
[:db :contacts/contacts "bob" :system-tags])
#{:tribute-to-talk/paid})))
(testing "change is persisted"
(is (:data-store/tx result)))))
#{:tribute-to-talk/paid})))))
(deftest mark-tribute-received
(let [result (whitelist/mark-tribute-received {:db {}} "bob")]
@ -64,9 +62,7 @@
(testing "contact was tagged as tribute paid"
(is (= (get-in result
[:db :contacts/contacts "bob" :system-tags])
#{:tribute-to-talk/received})))
(testing "change is persisted"
(is (:data-store/tx result)))))
#{:tribute-to-talk/received})))))
(def sender-pk "0x04263d74e55775280e75b4a4e9a45ba59fc372793a869c5d9c4fa2100556d9963e3f4fbfa1724ec94a46e6da057540ab248ed1f5eb956e36e3129ecd50fade2c97")
(def sender-address "0xdff1a5e4e57d9723b3294e0f4413372e3ea9a8ff")