Refactor adding subscriptions + basic tests
This commit is contained in:
parent
df83cbb987
commit
55164b8eac
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.bots.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.chat.models.input :as input-model]
|
||||
[taoensso.timbre :as log]))
|
||||
|
@ -12,65 +13,85 @@
|
|||
{}
|
||||
sub-params))
|
||||
|
||||
;; TODO(janherich): do this properly instead of the ugly hack with hardcoded bot-db key
|
||||
;; und uneffective lookup of the owner of selected-chat-command
|
||||
(defn- check-subscriptions-fx
|
||||
[{:keys [bot-db bot-subscriptions chats current-chat-id] :as app-db} path]
|
||||
(let [owner-id (some-> app-db
|
||||
(input-model/selected-chat-command current-chat-id (get-in app-db [:chats current-chat-id :input-text]))
|
||||
:command
|
||||
:owner-id)]
|
||||
(when-let [subscriptions (and owner-id (get-in bot-subscriptions (concat [owner-id] [path])))]
|
||||
{:call-jail-function-n
|
||||
(for [[sub-name sub-params] subscriptions]
|
||||
{:chat-id owner-id
|
||||
:function :subscription
|
||||
:parameters {:name sub-name
|
||||
:subscriptions (subscription-values sub-params
|
||||
(get bot-db current-chat-id))}
|
||||
:callback-events-creator (fn [jail-response]
|
||||
[[::calculated-subscription
|
||||
{:bot current-chat-id
|
||||
:path [sub-name]
|
||||
:result jail-response}]])})})))
|
||||
[{:keys [bot-db bot-subscriptions] :as app-db} {:keys [bot path]}]
|
||||
(when-let [subscriptions (and bot (get-in bot-subscriptions (concat [bot] [path])))]
|
||||
{:call-jail-function-n
|
||||
(for [[sub-name sub-params] subscriptions]
|
||||
{:chat-id bot
|
||||
:function :subscription
|
||||
:parameters {:name sub-name
|
||||
:subscriptions (subscription-values sub-params (get bot-db bot))}
|
||||
:callback-events-creator (fn [jail-response]
|
||||
[[::calculated-subscription
|
||||
{:bot bot
|
||||
:path [sub-name]
|
||||
:result jail-response}]])})}))
|
||||
|
||||
(defn set-in-bot-db
|
||||
[{:keys [current-chat-id] :as app-db} {:keys [bot path value] :as params}]
|
||||
(let [bot (or bot current-chat-id)
|
||||
new-db (assoc-in app-db (concat [:bot-db bot] path) value)]
|
||||
"Associates value at specified path in bot-db and checks if there are any subscriptions
|
||||
dependent on that path, if yes, adds effects for calling jail-functions to recalculate
|
||||
relevant subscriptions."
|
||||
[app-db {:keys [bot path value] :as params}]
|
||||
(let [new-db (assoc-in app-db (concat [:bot-db bot] path) value)]
|
||||
(merge {:db new-db}
|
||||
(check-subscriptions-fx new-db path))))
|
||||
(check-subscriptions-fx new-db params))))
|
||||
|
||||
(defn update-bot-db
|
||||
[{:keys [current-chat-id] :as app-db} {:keys [bot db]}]
|
||||
(let [bot (or bot current-chat-id)]
|
||||
(update-in app-db [:bot-db bot] merge db)))
|
||||
[app-db {:keys [bot db]}]
|
||||
(update-in app-db [:bot-db bot] merge db))
|
||||
|
||||
(defn clear-bot-db
|
||||
[{:keys [current-chat-id] :as app-db}]
|
||||
(assoc-in app-db [:bot-db current-chat-id] nil))
|
||||
[app-db bot-id]
|
||||
(assoc-in app-db [:bot-db bot-id] nil))
|
||||
|
||||
(def ^:private keywordize-vector (partial mapv keyword))
|
||||
|
||||
;; TODO(janherich): do something with this horrible triple nested reduce so it's more readable
|
||||
(defn- transform-bot-subscriptions
|
||||
"Transforms bot subscriptions as returned from jail in the following format:
|
||||
|
||||
`{:calculatedFee {:subscriptions {:value [\"sliderValue\"]
|
||||
:tx [\"transaction\"]}}
|
||||
:feeExplanation {:subscriptions {:value [\"sliderValue\"]}}}`
|
||||
|
||||
into data-structure better suited for subscription lookups based on changes
|
||||
in `:bot-db`:
|
||||
|
||||
`{[:sliderValue] {:calculatedFee {:value [:sliderValue]
|
||||
:tx [:transaction]}
|
||||
:feeExplanation {:value [:sliderValue]}}
|
||||
[:transaction] {:calculatedFee {:value [:sliderValue]
|
||||
:tx [:transaction]}}}`
|
||||
|
||||
In the resulting data-structure, the top level keys are the (keywordized) paths
|
||||
in the `:bot-db` data structure, so it's quick and easy to look-up all the
|
||||
subscriptions which must be recalculated when something in their path changes."
|
||||
[bot-subscriptions]
|
||||
(reduce-kv (fn [acc sub-key {:keys [subscriptions]}]
|
||||
(reduce-kv (fn [acc sub-param-key sub-param-path]
|
||||
(update acc
|
||||
(keywordize-vector sub-param-path)
|
||||
assoc sub-key
|
||||
(utils/map-values subscriptions keywordize-vector)))
|
||||
acc
|
||||
subscriptions))
|
||||
{}
|
||||
bot-subscriptions))
|
||||
|
||||
(defn add-active-bot-subscriptions
|
||||
"Add subscriptions for selected bot identities into app-db"
|
||||
[app-db bot-identities]
|
||||
(let [relevant-bots (select-keys (:contacts/contacts app-db) bot-identities)
|
||||
active-subscriptions (reduce (fn [acc [bot-id {:keys [subscriptions]}]]
|
||||
(reduce (fn [acc [sub-key {:keys [subscriptions]}]]
|
||||
(reduce (fn [acc [sub-param-key sub-param-path]]
|
||||
(update-in acc [bot-id (keywordize-vector sub-param-path)]
|
||||
assoc sub-key (into {}
|
||||
(map (fn [[k v]]
|
||||
[k (keywordize-vector v)]))
|
||||
subscriptions)))
|
||||
acc
|
||||
subscriptions))
|
||||
acc
|
||||
subscriptions))
|
||||
{}
|
||||
relevant-bots)]
|
||||
(assoc app-db :bot-subscriptions active-subscriptions)))
|
||||
(assoc app-db :bot-subscriptions (-> app-db
|
||||
:contacts/contacts
|
||||
(select-keys bot-identities)
|
||||
(utils/map-values (comp transform-bot-subscriptions :subscriptions)))))
|
||||
|
||||
(defn calculated-subscription
|
||||
[db {:keys [bot path]
|
||||
{:keys [error result]} :result}]
|
||||
(if error
|
||||
db
|
||||
(assoc-in db (concat [:bot-db bot] path) (:returned result))))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
|
@ -89,8 +110,5 @@
|
|||
(handlers/register-handler-db
|
||||
::calculated-subscription
|
||||
[re-frame/trim-v]
|
||||
(fn [db [{:keys [bot path]
|
||||
{:keys [error result]} :result}]]
|
||||
(if error
|
||||
db
|
||||
(assoc-in db (concat [:bot-db bot] path) (:returned result)))))
|
||||
(fn [db [params]]
|
||||
(calculated-subscription db params)))
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
(ns status-im.bots.subs
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]))
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.chat.models.input :as input-model]))
|
||||
|
||||
(reg-sub
|
||||
(re-frame/reg-sub
|
||||
:current-bot-db
|
||||
(fn [db]
|
||||
(let [chat-id (subscribe [:get-current-chat-id])]
|
||||
(get-in db [:bot-db @chat-id]))))
|
||||
(let [current-chat-id (re-frame/subscribe [:get-current-chat-id])
|
||||
command-owner (-> db
|
||||
(input-model/selected-chat-command @current-chat-id)
|
||||
:command
|
||||
:owner-id)]
|
||||
[command-owner (get-in db [:bot-db command-owner])])))
|
||||
|
|
|
@ -52,9 +52,7 @@
|
|||
|
||||
(defn update-suggestions
|
||||
"Update suggestions for current chat input, takes db as the only argument
|
||||
and returns map with keys :db (new db with up-to-date suggestions) and (optionally)
|
||||
:call-jail-function with jail function call params, if request to jail needs
|
||||
to be made as a result of suggestions update."
|
||||
and returns new db with up-to date suggestions"
|
||||
[{:keys [chats current-chat-id] :as db}]
|
||||
(let [chat-text (str/trim (or (get-in chats [current-chat-id :input-text]) ""))
|
||||
requests (->> (commands-model/get-possible-requests db)
|
||||
|
@ -73,7 +71,7 @@
|
|||
(and dapp?
|
||||
(str/blank? chat-text))
|
||||
(assoc-in [:chats current-chat-id :parameter-boxes :message] nil))]
|
||||
{:db new-db}))
|
||||
new-db))
|
||||
|
||||
(defn set-chat-input-text
|
||||
"Set input text for current-chat and updates suggestions relevant to current input.
|
||||
|
@ -131,7 +129,7 @@
|
|||
seq-params? (-> (input-model/selected-chat-command db current-chat-id)
|
||||
(get-in [:command :sequential-params]))]
|
||||
(if seq-params?
|
||||
{:db (set-chat-seq-arg-input-text db arg)}
|
||||
(set-chat-seq-arg-input-text db arg)
|
||||
(let [arg (str/replace arg (re-pattern const/arg-wrapping-char) "")
|
||||
command-name (first command)
|
||||
command-args (into [] (rest command))
|
||||
|
@ -155,7 +153,7 @@
|
|||
(let [parameter-index (input-model/argument-position db)]
|
||||
(when (and command (> parameter-index -1))
|
||||
(let [data (get-in db [:local-storage current-chat-id])
|
||||
bot-db (get bot-db (or bot current-chat-id))
|
||||
bot-db (get bot-db owner-id)
|
||||
path [(if (= :command type) :commands :responses)
|
||||
[name
|
||||
(if (= :command type)
|
||||
|
@ -176,7 +174,7 @@
|
|||
:from current-account-id
|
||||
:to to}
|
||||
(input-model/command-dependent-context-params current-chat-id command))}]
|
||||
{:call-jail {:jail-id (or bot owner-id current-chat-id)
|
||||
{:call-jail {:jail-id owner-id
|
||||
:path path
|
||||
:params params
|
||||
:callback-events-creator (fn [jail-response]
|
||||
|
@ -214,9 +212,9 @@
|
|||
(defn select-chat-input-command
|
||||
"Selects command + (optional) arguments as input for active chat"
|
||||
[{:keys [current-chat-id chat-ui-props] :as db}
|
||||
{:keys [prefill prefill-bot-db sequential-params name] :as command} metadata prevent-auto-focus?]
|
||||
{:keys [prefill prefill-bot-db sequential-params name owner-id] :as command} metadata prevent-auto-focus?]
|
||||
(let [db' (-> db
|
||||
bots-events/clear-bot-db
|
||||
(bots-events/clear-bot-db owner-id)
|
||||
clear-seq-arguments
|
||||
(model/set-chat-ui-props {:show-suggestions? false
|
||||
:show-emoji? false
|
||||
|
@ -230,7 +228,8 @@
|
|||
(input-model/join-command-args prefill)))))
|
||||
fx (assoc (load-chat-parameter-box db' command) :db db')]
|
||||
(cond-> fx
|
||||
prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db})
|
||||
prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db
|
||||
:bot owner-id})
|
||||
|
||||
(not (and sequential-params
|
||||
prevent-auto-focus?))
|
||||
|
@ -246,15 +245,18 @@
|
|||
|
||||
(defn set-contact-as-command-argument
|
||||
"Sets contact as command argument for active chat"
|
||||
[db {:keys [bot-db-key contact arg-index]}]
|
||||
[{:keys [current-chat-id] :as db} {:keys [bot-db-key contact arg-index]}]
|
||||
(let [name (str/replace (:name contact) (re-pattern const/arg-wrapping-char) "")
|
||||
contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])]
|
||||
(-> (set-command-argument db arg-index name true)
|
||||
(as-> fx
|
||||
(merge fx (bots-events/set-in-bot-db
|
||||
(:db fx)
|
||||
{:path [:public (keyword bot-db-key)]
|
||||
:value contact})))
|
||||
contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])
|
||||
command-owner (-> db
|
||||
(input-model/selected-chat-command current-chat-id)
|
||||
:command
|
||||
:owner-id)]
|
||||
(-> db
|
||||
(set-command-argument arg-index name true)
|
||||
(bots-events/set-in-bot-db {:bot command-owner
|
||||
:path [:public (keyword bot-db-key)]
|
||||
:value contact})
|
||||
(as-> fx
|
||||
(let [{:keys [current-chat-id]
|
||||
:as new-db} (:db fx)
|
||||
|
@ -283,7 +285,7 @@
|
|||
{:url (i18n/get-contact-translated chat-id :dapp-url dapp-url)
|
||||
:name (i18n/get-contact-translated chat-id :name name)}))
|
||||
owner-id (:owner-id command)
|
||||
bot-db (get bot-db chat-id)
|
||||
bot-db (get bot-db owner-id)
|
||||
params (merge (input-model/args->params content)
|
||||
{:bot-db bot-db
|
||||
:metadata metadata})
|
||||
|
@ -374,10 +376,10 @@
|
|||
(fn [db [data]]
|
||||
(set-chat-input-metadata db data)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
(handlers/register-handler-db
|
||||
:set-command-argument
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [[index arg move-to-next?]]]
|
||||
(fn [db [[index arg move-to-next?]]]
|
||||
(set-command-argument db index arg move-to-next?)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
@ -393,9 +395,9 @@
|
|||
(when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
{::blur-rn-component cmp-ref})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
(handlers/register-handler-db
|
||||
:update-suggestions
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [db _]
|
||||
(update-suggestions db)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
@ -443,18 +445,18 @@
|
|||
[re-frame/trim-v]
|
||||
(fn [{{:keys [current-public-key current-chat-id]
|
||||
:accounts/keys [current-account-id] :as db} :db} [{:keys [command] :as command-message}]]
|
||||
(-> db
|
||||
clear-seq-arguments
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
(model/set-chat-ui-props {:sending-in-progress? false})
|
||||
update-suggestions
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
(assoc :dispatch [:check-commands-handlers! {:message (get-in db [:chats current-chat-id :input-text])
|
||||
:command command-message
|
||||
:chat-id current-chat-id
|
||||
:identity current-public-key
|
||||
:address current-account-id}]))))
|
||||
{:db (-> db
|
||||
clear-seq-arguments
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
(model/set-chat-ui-props {:sending-in-progress? false})
|
||||
update-suggestions)
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
:dispatch [:check-commands-handlers! {:message (get-in db [:chats current-chat-id :input-text])
|
||||
:command command-message
|
||||
:chat-id current-chat-id
|
||||
:identity current-public-key
|
||||
:address current-account-id}]}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::check-command-type
|
||||
|
@ -500,15 +502,15 @@
|
|||
;; no command detected, when not empty, proceed by sending text message without command processing
|
||||
(if (str/blank? input-text)
|
||||
{:db db}
|
||||
(-> db
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
update-suggestions
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
(assoc :dispatch [:prepare-message {:message input-text
|
||||
:chat-id current-chat-id
|
||||
:identity current-public-key
|
||||
:address (:accounts/current-account-id db)}])))))))
|
||||
{:db (-> db
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
update-suggestions)
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
:dispatch [:prepare-message {:message input-text
|
||||
:chat-id current-chat-id
|
||||
:identity current-public-key
|
||||
:address (:accounts/current-account-id db)}]})))))
|
||||
|
||||
;; TODO: remove this handler and leave only helper fn once all invocations are refactored
|
||||
(handlers/register-handler-db
|
||||
|
@ -561,10 +563,10 @@
|
|||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
command (input-model/selected-chat-command db current-chat-id input-text)]
|
||||
(if (get-in command [:command :sequential-params])
|
||||
(-> (set-command-argument db 0 "" false)
|
||||
(update :db set-chat-seq-arg-input-text "")
|
||||
(as-> fx
|
||||
(merge fx (load-chat-parameter-box (:db fx) (:command command)))))
|
||||
(-> db
|
||||
(set-command-argument 0 "" false)
|
||||
(set-chat-seq-arg-input-text "")
|
||||
(load-chat-parameter-box (:command command)))
|
||||
(let [arg-pos (input-model/argument-position db)]
|
||||
(when (pos? arg-pos)
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
|
@ -585,9 +587,9 @@
|
|||
(fn [{:keys [db]} [params]]
|
||||
(set-contact-as-command-argument db params)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
(handlers/register-handler-db
|
||||
:show-suggestions
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(model/toggle-chat-ui-prop :show-suggestions?)
|
||||
(model/set-chat-ui-props {:validation-messages nil})
|
||||
|
|
|
@ -11,27 +11,21 @@
|
|||
[status-im.data-store.messages :as msg-store]))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:pop-up-chat?
|
||||
(fn [cofx]
|
||||
(assoc cofx :pop-up-chat? (fn [chat-id]
|
||||
(or (not (chat-store/exists? chat-id))
|
||||
(chat-store/is-active? chat-id))))))
|
||||
:pop-up-chat?
|
||||
(fn [cofx]
|
||||
(assoc cofx :pop-up-chat? (fn [chat-id]
|
||||
(or (not (chat-store/exists? chat-id))
|
||||
(chat-store/is-active? chat-id))))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:message-exists?
|
||||
(fn [cofx]
|
||||
(assoc cofx :message-exists? msg-store/exists?)))
|
||||
:message-exists?
|
||||
(fn [cofx]
|
||||
(assoc cofx :message-exists? msg-store/exists?)))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-last-clock-value
|
||||
(fn [cofx]
|
||||
(assoc cofx :get-last-clock-value msg-store/get-last-clock-value)))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:current-timestamp
|
||||
(fn [cofx]
|
||||
;; TODO (janherich) why is actual timestmap generation in random namespace ?
|
||||
(assoc cofx :current-timestamp (random/timestamp))))
|
||||
:get-last-clock-value
|
||||
(fn [cofx]
|
||||
(assoc cofx :get-last-clock-value msg-store/get-last-clock-value)))
|
||||
|
||||
(defn- get-current-identity
|
||||
[{:accounts/keys [accounts current-account-id]}]
|
||||
|
@ -39,7 +33,7 @@
|
|||
|
||||
(defn add-message
|
||||
[{:keys [db message-exists? get-last-stored-message pop-up-chat?
|
||||
get-last-clock-value current-timestamp random-id]}
|
||||
get-last-clock-value now random-id]}
|
||||
{:keys [from group-id chat-id content-type
|
||||
message-id timestamp clock-value]
|
||||
:as message
|
||||
|
@ -57,7 +51,7 @@
|
|||
(get-last-stored-message chat-identifier)
|
||||
message)
|
||||
:chat-id chat-identifier
|
||||
:timestamp (or timestamp current-timestamp)
|
||||
:timestamp (or timestamp now)
|
||||
:clock-value (clocks/receive
|
||||
clock-value
|
||||
(get-last-clock-value chat-identifier)))]
|
||||
|
@ -68,8 +62,7 @@
|
|||
(assoc-in [:chats chat-identifier :last-message] message))
|
||||
:dispatch-n [[:upsert-chat! {:chat-id chat-identifier
|
||||
:group-chat group-chat?}]
|
||||
[:request-command-message-data enriched-message :short-preview]
|
||||
[:update-suggestions]]
|
||||
[:request-command-message-data enriched-message :short-preview]]
|
||||
:save-message (dissoc enriched-message :new?)}
|
||||
|
||||
(get-in enriched-message [:content :command])
|
||||
|
@ -77,7 +70,7 @@
|
|||
|
||||
(= (:content-type enriched-message) const/content-type-command-request)
|
||||
(update :dispatch-n conj [:add-request chat-identifier enriched-message])
|
||||
|
||||
;; TODO(janherich) this shouldn't be dispatch, but plain function call, refactor after adding requests is refactored
|
||||
true
|
||||
(update :dispatch-n conj [:update-suggestions])))
|
||||
{:db db})))
|
||||
|
@ -85,8 +78,7 @@
|
|||
(def ^:private receive-interceptors
|
||||
[(re-frame/inject-cofx :message-exists?) (re-frame/inject-cofx :get-last-stored-message)
|
||||
(re-frame/inject-cofx :pop-up-chat?) (re-frame/inject-cofx :get-last-clock-value)
|
||||
(re-frame/inject-cofx :current-timestamp) (re-frame/inject-cofx :random-id)
|
||||
re-frame/trim-v])
|
||||
(re-frame/inject-cofx :random-id) re-frame/trim-v])
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:received-protocol-message!
|
||||
|
|
|
@ -218,15 +218,16 @@
|
|||
|
||||
(register-handler :received-bot-response
|
||||
(u/side-effect!
|
||||
(fn [{:contacts/keys [contacts]} [_ {:keys [chat-id] :as params} {:keys [result] :as data}]]
|
||||
(fn [{:contacts/keys [contacts]} [_ {:keys [chat-id] :as params} {:keys [result bot-id] :as data}]]
|
||||
(let [{:keys [returned context]} result
|
||||
{:keys [markup text-message err]} returned
|
||||
{:keys [log-messages update-db default-db]} context
|
||||
content (or err text-message)]
|
||||
(when update-db
|
||||
(dispatch [:update-bot-db {:bot chat-id
|
||||
(dispatch [:update-bot-db {:bot bot-id
|
||||
:db update-db}]))
|
||||
(dispatch [:suggestions-handler (assoc params
|
||||
:bot-id bot-id
|
||||
:result data
|
||||
:default-db default-db)])
|
||||
(doseq [message log-messages]
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
(defview parameter-box-container []
|
||||
[{:keys [markup]} [:chat-parameter-box]
|
||||
bot-db [:current-bot-db]]
|
||||
bot-id-bot-db [:current-bot-db]]
|
||||
(when markup
|
||||
(command-utils/generate-hiccup markup bot-db)))
|
||||
(command-utils/generate-hiccup markup (first bot-id-bot-db) (second bot-id-bot-db))))
|
||||
|
||||
(defview parameter-box-view []
|
||||
[show-parameter-box? [:show-parameter-box?]
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
(defn suggestions-handler!
|
||||
[{:keys [chats] :as db}
|
||||
[{:keys [chat-id default-db command parameter-index result]}]]
|
||||
[{:keys [chat-id bot-id default-db command parameter-index result]}]]
|
||||
(let [{:keys [markup height] :as returned} (get-in result [:result :returned])
|
||||
contains-markup? (contains? returned :markup)
|
||||
current-input (get-in chats [chat-id :input-text])
|
||||
|
@ -47,36 +47,35 @@
|
|||
(when (and contains-markup? path (not= (get-in db path) markup))
|
||||
(dispatch [:set-in path returned])
|
||||
(when default-db
|
||||
(dispatch [:update-bot-db {:bot chat-id
|
||||
(dispatch [:update-bot-db {:bot bot-id
|
||||
:db default-db}])))))
|
||||
|
||||
(defn suggestions-events-handler!
|
||||
[{:keys [current-chat-id bot-db] :as db} [[n & data :as ev] val]]
|
||||
(log/debug "Suggestion event: " n (first data) val)
|
||||
(let [{:keys [dapp?]} (get-in db [:contacts/contacts current-chat-id])]
|
||||
(case (keyword n)
|
||||
:set-command-argument
|
||||
(let [[index value move-to-next?] (first data)]
|
||||
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||
:set-value
|
||||
(dispatch [:set-chat-input-text (first data)])
|
||||
:set
|
||||
(let [opts {:bot current-chat-id
|
||||
:path (mapv keyword data)
|
||||
:value val}]
|
||||
(dispatch [:set-in-bot-db opts]))
|
||||
:set-command-argument-from-db
|
||||
(let [[index arg move-to-next?] (first data)
|
||||
path (keyword arg)
|
||||
value (str (get-in bot-db [current-chat-id path]))]
|
||||
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||
:set-value-from-db
|
||||
(let [path (keyword (first data))
|
||||
value (str (get-in bot-db [current-chat-id path]))]
|
||||
(dispatch [:set-chat-input-text value]))
|
||||
:focus-input
|
||||
(dispatch [:chat-input-focus :input-ref])
|
||||
nil)))
|
||||
[{:keys [bot-db] :as db} [bot-id [n & data :as ev] val]]
|
||||
(log/debug "Suggestion event: " n (first data) val)
|
||||
(case (keyword n)
|
||||
:set-command-argument
|
||||
(let [[index value move-to-next?] (first data)]
|
||||
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||
:set-value
|
||||
(dispatch [:set-chat-input-text (first data)])
|
||||
:set
|
||||
(let [opts {:bot bot-id
|
||||
:path (mapv keyword data)
|
||||
:value val}]
|
||||
(dispatch [:set-in-bot-db opts]))
|
||||
:set-command-argument-from-db
|
||||
(let [[index arg move-to-next?] (first data)
|
||||
path (keyword arg)
|
||||
value (str (get-in bot-db [bot-id path]))]
|
||||
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||
:set-value-from-db
|
||||
(let [path (keyword (first data))
|
||||
value (str (get-in bot-db [bot-id path]))]
|
||||
(dispatch [:set-chat-input-text value]))
|
||||
:focus-input
|
||||
(dispatch [:chat-input-focus :input-ref])
|
||||
nil))
|
||||
|
||||
(defn print-error-message! [message]
|
||||
(fn [_ params]
|
||||
|
|
|
@ -45,31 +45,30 @@
|
|||
|
||||
(def events #{:onPress :onValueChange :onSlidingComplete})
|
||||
|
||||
(defn wrap-event [[_ event]]
|
||||
(let [data (gensym)]
|
||||
#(dispatch [:suggestions-event! (update event 0 keyword) %])))
|
||||
(defn wrap-event [[_ event] bot-id]
|
||||
#(dispatch [:suggestions-event! bot-id (update event 0 keyword) %]))
|
||||
|
||||
(defn check-events [m]
|
||||
(defn check-events [m bot-id]
|
||||
(let [ks (set (keys m))
|
||||
evs (set/intersection ks events)]
|
||||
(reduce #(update %1 %2 wrap-event) m evs)))
|
||||
(reduce #(update %1 %2 wrap-event bot-id) m evs)))
|
||||
|
||||
(defn generate-hiccup
|
||||
([markup]
|
||||
(generate-hiccup markup {}))
|
||||
([markup data]
|
||||
(generate-hiccup markup nil {}))
|
||||
([markup bot-id bot-db]
|
||||
(w/prewalk
|
||||
(fn [el]
|
||||
(cond
|
||||
|
||||
(and (vector? el) (= "subscribe" (first el)))
|
||||
(let [path (mapv keyword (second el))]
|
||||
(get-in data path))
|
||||
(get-in bot-db path))
|
||||
|
||||
(and (vector? el) (string? (first el)))
|
||||
(-> el
|
||||
(update 0 get-element)
|
||||
(update 1 check-events))
|
||||
(update 1 check-events bot-id))
|
||||
|
||||
:else el))
|
||||
markup)))
|
||||
|
|
|
@ -120,9 +120,9 @@
|
|||
(when status
|
||||
(call-module #(.discardTransaction status id))))
|
||||
|
||||
(defn parse-jail [chat-id file callback]
|
||||
(defn parse-jail [bot-id file callback]
|
||||
(when status
|
||||
(call-module #(.parseJail status chat-id file callback))))
|
||||
(call-module #(.parseJail status bot-id file callback))))
|
||||
|
||||
(defn execute-call [{:keys [jail-id path params callback]}]
|
||||
(when status
|
||||
|
|
|
@ -30,10 +30,11 @@
|
|||
(handlers/register-handler-fx
|
||||
:profile/send-transaction
|
||||
[trim-v]
|
||||
(fn [_ [chat-id]]
|
||||
{:dispatch [:navigate-to :chat chat-id]
|
||||
;;TODO get rid of timeout
|
||||
:dispatch-later [{:ms 100 :dispatch [:select-chat-input-command {:name "send"}]}]}))
|
||||
(fn [{:keys [db]} [chat-id]]
|
||||
(let [send-command (first (get-in db [:contacts/contacts "transactor-personal" :commands :send]))]
|
||||
{:dispatch [:navigate-to :chat chat-id]
|
||||
;;TODO get rid of timeout
|
||||
:dispatch-later [{:ms 100 :dispatch [:select-chat-input-command send-command]}]})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:profile/send-message
|
||||
|
@ -45,9 +46,10 @@
|
|||
:my-profile/update-phone-number
|
||||
;; Switch user to the console issuing the !phone command automatically to let him change his phone number.
|
||||
;; We allow to change phone number only from console because this requires entering SMS verification code.
|
||||
(fn [_ _]
|
||||
{:dispatch-n [[:navigate-to :chat console-chat-id]
|
||||
[:select-chat-input-command {:name "phone"}]]}))
|
||||
(fn [{:keys [db]} _]
|
||||
(let [phone-command (first (get-in db [:contacts/contacts "console" :responses :phone]))]
|
||||
{:dispatch-n [[:navigate-to :chat console-chat-id]
|
||||
[:select-chat-input-command phone-command]]})))
|
||||
|
||||
(defn get-current-account [{:keys [:accounts/current-account-id] :as db}]
|
||||
(get-in db [:accounts/accounts current-account-id]))
|
||||
|
|
|
@ -4,23 +4,26 @@
|
|||
[status-im.ui.screens.wallet.db :as wallet.db]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn chat-loaded-callback [amount]
|
||||
(defn chat-loaded-callback [request-command]
|
||||
(fn []
|
||||
(re-frame/dispatch [:select-chat-input-command {:name "request" :prefill [amount]}])
|
||||
(re-frame/dispatch [:select-chat-input-command request-command])
|
||||
;;TODO get rid of timeout
|
||||
(js/setTimeout #(re-frame/dispatch [:send-current-message]) 100)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet-send-request
|
||||
(fn [{{:wallet/keys [request-transaction]} :db} [_ {:keys [whisper-identity]}]]
|
||||
{:dispatch-n [[:navigate-back]
|
||||
[:navigate-to-clean :chat-list]
|
||||
[:add-chat-loaded-callback whisper-identity (chat-loaded-callback (:amount request-transaction))]
|
||||
[:start-chat whisper-identity]]}))
|
||||
(fn [{{:wallet/keys [request-transaction] :as db} :db} [_ {:keys [whisper-identity]}]]
|
||||
(let [request-command (first (get-in db [:contacts/contacts "transactor-personal" :commands :request]))]
|
||||
{:dispatch-n [[:navigate-back]
|
||||
[:navigate-to-clean :chat-list]
|
||||
[:add-chat-loaded-callback whisper-identity (chat-loaded-callback
|
||||
(assoc request-command
|
||||
:prefill [(:amount request-transaction)]))]
|
||||
[:start-chat whisper-identity]]})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet-validate-request-amount
|
||||
(fn [{{:wallet/keys [request-transaction] :as db} :db} _]
|
||||
(let [amount (:amount request-transaction)
|
||||
error (wallet.db/get-amount-validation-error amount)]
|
||||
{:db (assoc-in db [:wallet/request-transaction :amount-error] error)})))
|
||||
{:db (assoc-in db [:wallet/request-transaction :amount-error] error)})))
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
title
|
||||
content
|
||||
(clj->js
|
||||
(vector (merge {:text (i18n/label :t/no)}
|
||||
(when on-cancel {:onPress on-cancel}))
|
||||
{:text (i18n/label :t/yes) :onPress on-accept})))))
|
||||
(vector (merge {:text (i18n/label :t/no)}
|
||||
(when on-cancel {:onPress on-cancel}))
|
||||
{:text (i18n/label :t/yes) :onPress on-accept})))))
|
||||
|
||||
(defn http-post
|
||||
([action data on-success]
|
||||
|
@ -125,3 +125,11 @@
|
|||
(if (contains? m k)
|
||||
(apply update m k f args)
|
||||
m))
|
||||
|
||||
(defn map-values
|
||||
"Efficiently apply function to all map values"
|
||||
[m f]
|
||||
(into {}
|
||||
(map (fn [[k v]]
|
||||
[k (f v)]))
|
||||
m))
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
(ns status-im.test.bots.events
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.bots.events :as bots-events]))
|
||||
|
||||
(def ^:private initial-db
|
||||
{:bot-db {}
|
||||
:bot-subscriptions {}
|
||||
:contacts/contacts
|
||||
{"bot1" {:subscriptions
|
||||
{:feeExplanation
|
||||
{:subscriptions {:fee ["sliderValue"]
|
||||
:tx ["transaction"]}}}}
|
||||
"bot2" {:subscriptions
|
||||
{:roundedValue
|
||||
{:subscriptions {:amount ["input"]}}}}
|
||||
"bot3" {:subscriptions
|
||||
{:warning
|
||||
{:subscriptions {:amount ["input"]}}}}}})
|
||||
|
||||
(deftest add-active-bot-subscriptions-test
|
||||
(testing "That active bot subscriptions are correctly transformed and added to db"
|
||||
(let [db (bots-events/add-active-bot-subscriptions initial-db #{"bot1" "bot3"})]
|
||||
(is (= #{"bot1" "bot3"} (-> db :bot-subscriptions keys set)))
|
||||
(is (= {[:sliderValue] {:feeExplanation {:fee [:sliderValue]
|
||||
:tx [:transaction]}}
|
||||
[:transaction] {:feeExplanation {:fee [:sliderValue]
|
||||
:tx [:transaction]}}}
|
||||
(-> db :bot-subscriptions (get "bot1")))))))
|
||||
|
||||
(defn- fake-subscription-call
|
||||
[db {:keys [chat-id parameters]}]
|
||||
(let [{:keys [name subscriptions]} parameters
|
||||
simulated-jail-response {:result {:returned {:sub-call-arg-map subscriptions}}}]
|
||||
(bots-events/calculated-subscription db {:bot chat-id
|
||||
:path [name]
|
||||
:result simulated-jail-response})))
|
||||
|
||||
(deftest set-in-bot-db-test
|
||||
(let [{:keys [db call-jail-function-n]} (-> initial-db
|
||||
(bots-events/add-active-bot-subscriptions #{"bot1" "bot2"})
|
||||
(bots-events/set-in-bot-db {:bot "bot1"
|
||||
:path [:sliderValue]
|
||||
:value 2}))
|
||||
new-db (reduce fake-subscription-call db call-jail-function-n)]
|
||||
(testing "That setting in value in bot-db correctly updates bot-db"
|
||||
(is (= 2 (get-in new-db [:bot-db "bot1" :sliderValue]))))
|
||||
(testing "That subscriptions are fired-off"
|
||||
(is (= {:sub-call-arg-map {:fee 2
|
||||
:tx nil}}
|
||||
(get-in new-db [:bot-db "bot1" :feeExplanation]))))))
|
|
@ -6,6 +6,7 @@
|
|||
[status-im.test.wallet.events]
|
||||
[status-im.test.wallet.transactions.subs]
|
||||
[status-im.test.profile.events]
|
||||
[status-im.test.bots.events]
|
||||
[status-im.test.chat.models.input]
|
||||
[status-im.test.components.main-tabs]
|
||||
[status-im.test.i18n]
|
||||
|
@ -35,6 +36,7 @@
|
|||
;;'status-im.test.contacts.events
|
||||
'status-im.test.profile.events
|
||||
'status-im.test.wallet.events
|
||||
'status-im.test.bots.events
|
||||
'status-im.test.wallet.transactions.subs
|
||||
'status-im.test.chat.models.input
|
||||
'status-im.test.components.main-tabs
|
||||
|
|
|
@ -36,3 +36,8 @@
|
|||
(is (= {:a 1} (u/update-if-present {:a 0} :a inc)))
|
||||
(is (= {:a 2} (u/update-if-present {:a 0} :a + 2)))
|
||||
(is (= {:a 0} (u/update-if-present {:a 0} :b inc))))
|
||||
|
||||
(deftest map-values-test
|
||||
(is (= {} (u/map-values {} inc)))
|
||||
(is (= {:a 1} (u/map-values {:a 0} inc)))
|
||||
(is (= {:a 1 :b 2} (u/map-values {:a 0 :b 1} inc))))
|
||||
|
|
Loading…
Reference in New Issue