[refactor] move contact.subs and utils.contacts to contact.db

functions defined in subs need to be reusable and testable independently
from re-frame framework. they are moved into db namespace for that purpose

Signed-off-by: yenda <eric@status.im>
This commit is contained in:
yenda 2018-11-19 12:23:56 +01:00
parent eed610c46e
commit 1ba7feb439
No known key found for this signature in database
GPG Key ID: 0095623C0069DCE6
10 changed files with 227 additions and 206 deletions

View File

@ -7,7 +7,7 @@
[status-im.i18n :as i18n]
[status-im.utils.core :as utils]
[status-im.utils.config :as config]
[status-im.utils.contacts :as utils.contacts]
[status-im.contact.db :as contact.db]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.datetime :as time]
[status-im.transport.message.group-chat :as message.group-chat]
@ -96,7 +96,7 @@
(let [chat-name' (chat.db/chat-name (get-in db [:chats chat-id]) from)
contact-name' (if-let [contact-name (get-in db [:contacts/contacts from :name])]
contact-name
(:name (utils.contacts/public-key->new-contact from)))
(:name (contact.db/public-key->new-contact from)))
shown-chat-name (when-not (= chat-name' contact-name') chat-name') ; No point in repeating contact name if the chat name already contains the same name
timestamp' (when-not (< (time/seconds-ago (time/to-date timestamp)) 15)
(str " @ " (time/to-short-str timestamp)))

View File

@ -1,18 +1,16 @@
(ns status-im.contact.core
(:require [status-im.accounts.db :as accounts.db]
[status-im.data-store.contacts :as contacts-store]
[status-im.transport.message.protocol :as protocol]
[status-im.transport.message.contact :as message.contact]
[status-im.utils.contacts :as utils.contacts]
[status-im.utils.fx :as fx]
[re-frame.core :as re-frame]
(:require [re-frame.core :as re-frame]
[status-im.accounts.db :as accounts.db]
[status-im.chat.models :as chat.models]
[status-im.contact.db :as contact.db]
[status-im.data-store.contacts :as contacts-store]
[status-im.i18n :as i18n]
[status-im.transport.message.contact :as message.contact]
[status-im.transport.message.protocol :as protocol]
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.js-resources :as js-res]
[status-im.utils.utils :as utils]
[status-im.utils.fx :as fx]))
[status-im.utils.fx :as fx]
[status-im.utils.utils :as utils]))
(fx/defn load-contacts
[{:keys [db all-contacts]}]
@ -29,8 +27,8 @@
(defn build-contact [{{:keys [chats] :account/keys [account]
:contacts/keys [contacts]} :db} public-key]
(cond-> (assoc (or (get contacts public-key)
(utils.contacts/public-key->new-contact public-key))
:address (utils.contacts/public-key->address public-key))
(contact.db/public-key->new-contact public-key))
:address (contact.db/public-key->address public-key))
(= public-key (:public-key account)) (assoc :name (:name account))))
@ -110,7 +108,7 @@
:name name
:address (or address
(:address contact)
(utils.contacts/public-key->address public-key))
(contact.db/public-key->address public-key))
:last-updated timestamp-ms
;;NOTE (yenda) in case of concurrent contact request
:pending? (get contact :pending? true)}

View File

@ -1,5 +1,9 @@
(ns status-im.contact.db
(:require [cljs.spec.alpha :as spec]
[status-im.js-dependencies :as js-dependencies]
[status-im.utils.identicon :as identicon]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.ethereum.core :as ethereum]
status-im.utils.db))
;;;; DB
@ -77,3 +81,59 @@
(spec/def :contact/new-tag string?)
(spec/def :ui/contact (spec/keys :opt [:contact/new-tag]))
(defn public-key->new-contact [public-key]
{:name (gfycat/generate-gfy public-key)
:photo-path (identicon/identicon public-key)
:public-key public-key})
(defn public-key->address [public-key]
(let [length (count public-key)
normalized-key (case length
132 (subs public-key 4)
130 (subs public-key 2)
128 public-key
nil)]
(when normalized-key
(subs (.sha3 js-dependencies/Web3.prototype normalized-key #js {:encoding "hex"}) 26))))
(defn- contact-by-address [[_ contact] address]
(when (ethereum/address= (:address contact) address)
contact))
(defn find-contact-by-address [contacts address]
(some #(contact-by-address % address) contacts))
(defn sort-contacts
[contacts]
(sort (fn [c1 c2]
(let [name1 (or (:name c1) (:address c1) (:public-key c1))
name2 (or (:name c2) (:address c2) (:public-key c2))]
(compare (clojure.string/lower-case name1)
(clojure.string/lower-case name2))))
(vals contacts)))
(defn filter-dapps
[v dev-mode?]
(remove #(when-not dev-mode? (true? (:developer? %))) v))
(defn filter-group-contacts
[group-contacts contacts]
(let [group-contacts' (into #{} group-contacts)]
(filter #(group-contacts' (:public-key %)) contacts)))
(defn query-chat-contacts
[{:keys [contacts]} all-contacts query-fn]
(let [participant-set (into #{} (filter identity) contacts)]
(query-fn (comp participant-set :public-key) (vals all-contacts))))
(defn get-all-contacts-in-group-chat
[members contacts current-account]
(let [current-account-contact (-> current-account
(select-keys [:name :photo-path :public-key]))
all-contacts (assoc contacts (:public-key current-account-contact) current-account-contact)]
(->> members
(map #(or (get all-contacts %)
(public-key->new-contact %)))
(remove :dapp?)
(sort-by (comp clojure.string/lower-case :name)))))

View File

@ -1,164 +1,154 @@
(ns status-im.contact.subs
(:require [re-frame.core :refer [reg-sub subscribe]]
[status-im.utils.contacts :as utils.contacts]
[status-im.utils.identicon :as identicon]))
(:require [re-frame.core :as re-frame]
[status-im.utils.identicon :as identicon]
[status-im.contact.db :as contact.db]))
(reg-sub :get-current-contact-identity :contacts/identity)
(re-frame/reg-sub :get-current-contact-identity :contacts/identity)
(reg-sub :get-contacts :contacts/contacts)
(re-frame/reg-sub :get-contacts :contacts/contacts)
(reg-sub :get-dapps
(fn [db]
(:contacts/dapps db)))
(re-frame/reg-sub :get-dapps
(fn [db]
(:contacts/dapps db)))
(reg-sub :get-current-contact
:<- [:get-contacts]
:<- [:get-current-contact-identity]
(fn [[contacts identity]]
(contacts identity)))
(re-frame/reg-sub
:get-current-contact
:<- [:get-contacts]
:<- [:get-current-contact-identity]
(fn [[contacts identity]]
(contacts identity)))
(reg-sub :get-current-chat-contact
:<- [:get-contacts]
:<- [:get-current-chat-id]
(fn [[contacts chat-id]]
(get contacts chat-id)))
(re-frame/reg-sub
:get-current-chat-contact
:<- [:get-contacts]
:<- [:get-current-chat-id]
(fn [[contacts chat-id]]
(get contacts chat-id)))
(defn sort-contacts [contacts]
(sort (fn [c1 c2]
(let [name1 (or (:name c1) (:address c1) (:public-key c1))
name2 (or (:name c2) (:address c2) (:public-key c2))]
(compare (clojure.string/lower-case name1)
(clojure.string/lower-case name2))))
(vals contacts)))
(re-frame/reg-sub
:all-added-contacts
:<- [:get-contacts]
(fn [contacts]
(->> contacts
(remove (fn [[_ {:keys [pending? hide-contact?]}]]
(or pending? hide-contact?)))
(contact.db/sort-contacts))))
(reg-sub :all-added-contacts
:<- [:get-contacts]
(fn [contacts]
(->> contacts
(remove (fn [[_ {:keys [pending? hide-contact?]}]]
(or pending? hide-contact?)))
(sort-contacts))))
(re-frame/reg-sub
:all-added-people-contacts
:<- [:all-added-contacts]
(fn [contacts]
(remove :dapp? contacts)))
(reg-sub :all-added-people-contacts
:<- [:all-added-contacts]
(fn [contacts]
(remove :dapp? contacts)))
(re-frame/reg-sub
:all-dapps
:<- [:get-dapps]
:<- [:account/account]
(fn [[dapps {:keys [dev-mode?]}]]
(map (fn [m] (update m :data
#(contact.db/filter-dapps % dev-mode?)))
dapps)))
(defn- filter-dapps [v dev-mode?]
(remove #(when-not dev-mode? (true? (:developer? %))) v))
(re-frame/reg-sub
:get-people-in-current-chat
:<- [:get-current-chat-contacts]
(fn [contacts]
(remove #(true? (:dapp? %)) contacts)))
(reg-sub :all-dapps
:<- [:get-dapps]
:<- [:account/account]
(fn [[dapps {:keys [dev-mode?]}]]
(map (fn [m] (update m :data #(filter-dapps % dev-mode?))) dapps)))
(re-frame/reg-sub
:get-contact-by-identity
:<- [:get-contacts]
:<- [:get-current-chat]
(fn [[all-contacts {:keys [contacts]}] [_ identity]]
(let [identity' (or identity (first contacts))]
(or
(get all-contacts identity')
(contact.db/public-key->new-contact identity')))))
(reg-sub :get-people-in-current-chat
:<- [:get-current-chat-contacts]
(fn [contacts]
(remove #(true? (:dapp? %)) contacts)))
(re-frame/reg-sub
:contacts/dapps-by-name
:<- [:all-dapps]
(fn [dapps]
(reduce (fn [dapps-by-name category]
(merge dapps-by-name
(reduce (fn [acc {:keys [name] :as dapp}]
(assoc acc name dapp))
{}
(:data category))))
{}
dapps)))
(defn filter-group-contacts [group-contacts contacts]
(let [group-contacts' (into #{} group-contacts)]
(filter #(group-contacts' (:public-key %)) contacts)))
(re-frame/reg-sub
:get-contact-name-by-identity
:<- [:get-contacts]
:<- [:account/account]
(fn [[contacts current-account] [_ identity]]
(let [me? (= (:public-key current-account) identity)]
(if me?
(:name current-account)
(:name (contacts identity))))))
(reg-sub :get-contact-by-identity
:<- [:get-contacts]
:<- [:get-current-chat]
(fn [[all-contacts {:keys [contacts]}] [_ identity]]
(let [identity' (or identity (first contacts))]
(or
(get all-contacts identity')
(utils.contacts/public-key->new-contact identity')))))
(re-frame/reg-sub
:query-current-chat-contacts
:<- [:get-current-chat]
:<- [:get-contacts]
(fn [[chat contacts [_ query-fn]]]
(contact.db/query-chat-contacts chat contacts query-fn)))
(reg-sub :contacts/dapps-by-name
:<- [:all-dapps]
(fn [dapps]
(reduce (fn [dapps-by-name category]
(merge dapps-by-name
(reduce (fn [acc {:keys [name] :as dapp}]
(assoc acc name dapp))
{}
(:data category))))
{}
dapps)))
(re-frame/reg-sub
:get-all-contacts-not-in-current-chat
:<- [:query-current-chat-contacts remove]
(fn [contacts]
(->> contacts
(remove :dapp?)
(sort-by (comp clojure.string/lower-case :name)))))
(reg-sub :get-contact-name-by-identity
:<- [:get-contacts]
:<- [:account/account]
(fn [[contacts current-account] [_ identity]]
(let [me? (= (:public-key current-account) identity)]
(if me?
(:name current-account)
(:name (contacts identity))))))
(re-frame/reg-sub
:get-current-chat-contacts
:<- [:get-current-chat]
:<- [:get-contacts]
:<- [:account/account]
(fn [[{:keys [contacts]} all-contacts current-account]]
(contact.db/get-all-contacts-in-group-chat contacts all-contacts current-account)))
(defn query-chat-contacts [[{:keys [contacts]} all-contacts] [_ query-fn]]
(let [participant-set (into #{} (filter identity) contacts)]
(query-fn (comp participant-set :public-key) (vals all-contacts))))
(re-frame/reg-sub
:get-contacts-by-chat
(fn [[_ _ chat-id] _]
[(re-frame/subscribe [:get-chat chat-id])
(re-frame/subscribe [:get-contacts])])
(fn [[chat all-contacts [_ query-fn]]]
(contact.db/query-chat-contacts chat all-contacts query-fn)))
(reg-sub :query-current-chat-contacts
:<- [:get-current-chat]
:<- [:get-contacts]
query-chat-contacts)
(re-frame/reg-sub
:get-chat-photo
(fn [[_ chat-id] _]
[(re-frame/subscribe [:get-chat chat-id])
(re-frame/subscribe [:get-contacts-by-chat filter chat-id])])
(fn [[chat contacts] [_ chat-id]]
(when (and chat (not (:group-chat chat)))
(cond
(:photo-path chat)
(:photo-path chat)
(reg-sub :get-all-contacts-not-in-current-chat
:<- [:query-current-chat-contacts remove]
(fn [contacts]
(->> contacts
(remove :dapp?)
(sort-by (comp clojure.string/lower-case :name)))))
(pos? (count contacts))
(:photo-path (first contacts))
(defn get-all-contacts-in-group-chat
[members contacts current-account]
(let [current-account-contact (-> current-account
(select-keys [:name :photo-path :public-key]))
all-contacts (assoc contacts (:public-key current-account-contact) current-account-contact)]
(->> members
(map #(or (get all-contacts %)
(utils.contacts/public-key->new-contact %)))
(remove :dapp?)
(sort-by (comp clojure.string/lower-case :name)))))
:else
(identicon/identicon chat-id)))))
(reg-sub :get-current-chat-contacts
:<- [:get-current-chat]
:<- [:get-contacts]
:<- [:account/account]
(fn [[{:keys [contacts]} all-contacts current-account]]
(get-all-contacts-in-group-chat contacts all-contacts current-account)))
(re-frame/reg-sub
:get-contact-by-address
:<- [:get-contacts]
(fn [contacts [_ address]]
(contact.db/find-contact-by-address contacts address)))
(reg-sub :get-contacts-by-chat
(fn [[_ _ chat-id] _]
[(subscribe [:get-chat chat-id])
(subscribe [:get-contacts])])
query-chat-contacts)
(reg-sub :get-chat-photo
(fn [[_ chat-id] _]
[(subscribe [:get-chat chat-id])
(subscribe [:get-contacts-by-chat filter chat-id])])
(fn [[chat contacts] [_ chat-id]]
(when (and chat (not (:group-chat chat)))
(cond
(:photo-path chat)
(:photo-path chat)
(pos? (count contacts))
(:photo-path (first contacts))
:else
(identicon/identicon chat-id)))))
(reg-sub :get-contact-by-address
:<- [:get-contacts]
(fn [contacts [_ address]]
(utils.contacts/find-contact-by-address contacts address)))
(reg-sub :get-contacts-by-address
:<- [:get-contacts]
(fn [contacts]
(reduce (fn [acc [_ {:keys [address] :as contact}]]
(if address
(assoc acc address contact)
acc))
{}
contacts)))
(re-frame/reg-sub
:get-contacts-by-address
:<- [:get-contacts]
(fn [contacts]
(reduce (fn [acc [_ {:keys [address] :as contact}]]
(if address
(assoc acc address contact)
acc))
{}
contacts)))

View File

@ -20,7 +20,7 @@
[status-im.ui.screens.desktop.main.tabs.profile.views :as profile.views]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.screens.desktop.main.chat.styles :as styles]
[status-im.utils.contacts :as utils.contacts]
[status-im.contact.db :as contact.db]
[status-im.i18n :as i18n]
[status-im.ui.screens.desktop.main.chat.events :as chat.events]
[status-im.ui.screens.chat.message.message :as chat.message]))
@ -332,7 +332,7 @@
(views/defview chat-profile []
(views/letsubs [identity [:get-current-contact-identity]
maybe-contact [:get-current-contact]]
(let [contact (or maybe-contact (utils.contacts/public-key->new-contact identity))
(let [contact (or maybe-contact (contact.db/public-key->new-contact identity))
{:keys [pending? public-key]} contact]
[react/view {:style styles/chat-profile-body}
[profile.views/profile-badge contact]

View File

@ -1,15 +1,15 @@
(ns status-im.ui.screens.profile.contact.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.contact.db :as contact.db]
[status-im.i18n :as i18n]
[status-im.utils.contacts :as utils.contacts]
[status-im.ui.components.react :as react]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.screens.profile.contact.styles :as styles]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.screens.profile.components.styles :as profile.components.styles]
[status-im.ui.screens.profile.components.views :as profile.components]))
[status-im.ui.screens.profile.components.views :as profile.components]
[status-im.ui.screens.profile.contact.styles :as styles])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn profile-contact-toolbar []
[toolbar/toolbar {}
@ -64,7 +64,7 @@
(defview profile []
(letsubs [identity [:get-current-contact-identity]
maybe-contact [:get-current-contact]]
(let [contact (or maybe-contact (utils.contacts/public-key->new-contact identity))]
(let [contact (or maybe-contact (contact.db/public-key->new-contact identity))]
[react/view profile.components.styles/profile
[status-bar/status-bar]
[profile-contact-toolbar]

View File

@ -1,13 +1,13 @@
(ns status-im.ui.screens.wallet.choose-recipient.events
(:require [status-im.constants :as constants]
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.contact.db :as contact.db]
[status-im.i18n :as i18n]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.eip681 :as eip681]
[status-im.utils.handlers :as handlers]
[status-im.utils.money :as money]
[status-im.utils.ethereum.ens :as ens]
[re-frame.core :as re-frame]
[status-im.utils.contacts :as utils.contacts]))
[status-im.utils.handlers :as handlers]
[status-im.utils.money :as money]))
(handlers/register-handler-fx
:wallet/toggle-flashlight
@ -17,7 +17,7 @@
{:db (assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state)})))
(defn- find-address-name [db address]
(:name (utils.contacts/find-contact-by-address (:contacts/contacts db) address)))
(:name (contact.db/find-contact-by-address (:contacts/contacts db) address)))
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice public-key from-chat?]}]
{:pre [(not (nil? address))]}

View File

@ -1,27 +0,0 @@
(ns status-im.utils.contacts
(:require [status-im.js-dependencies :as js-dependencies]
[status-im.utils.identicon :as identicon]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.ethereum.core :as ethereum]))
(defn public-key->new-contact [public-key]
{:name (gfycat/generate-gfy public-key)
:photo-path (identicon/identicon public-key)
:public-key public-key})
(defn public-key->address [public-key]
(let [length (count public-key)
normalized-key (case length
132 (subs public-key 4)
130 (subs public-key 2)
128 public-key
nil)]
(when normalized-key
(subs (.sha3 js-dependencies/Web3.prototype normalized-key #js {:encoding "hex"}) 26))))
(defn- contact-by-address [[_ contact] address]
(when (ethereum/address= (:address contact) address)
contact))
(defn find-contact-by-address [contacts address]
(some #(contact-by-address % address) contacts))

View File

@ -1,7 +1,7 @@
(ns status-im.test.contacts.subs
(ns status-im.test.contacts.db
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.identicon :as identicon]
[status-im.contact.subs :as contacts-subs]))
[status-im.contact.db :as contact.db]))
(deftest contacts-subs
(testing "get-all-contacts-in-group-chat"
@ -35,9 +35,9 @@
:photo-path "photo2",
:public-key
"0x048a2f8b80c60f89a91b4c1316e56f75b087f446e7b8701ceca06a40142d8efe1f5aa36bd0fee9e248060a8d5207b43ae98bef4617c18c71e66f920f324869c09f"}]
(is (= (contacts-subs/get-all-contacts-in-group-chat chat-contact-ids
contacts
current-account)
(is (= (contact.db/get-all-contacts-in-group-chat chat-contact-ids
contacts
current-account)
[{:name "Snappy Impressive Leonberger"
:photo-path "generated"
:public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"}

View File

@ -1,6 +1,6 @@
(ns status-im.test.runner
(:require [doo.runner :refer-macros [doo-tests]]
[status-im.test.contacts.subs]
[status-im.test.contacts.db]
[status-im.test.data-store.chats]
[status-im.test.data-store.realm.core]
[status-im.test.extensions.core]
@ -69,8 +69,8 @@
(doo-tests
'status-im.test.utils.async
'status-im.test.chat.db
'status-im.test.contacts.db
'status-im.test.chat.models
'status-im.test.contacts.subs
'status-im.test.init.core
'status-im.test.data-store.chats
'status-im.test.data-store.realm.core