Allow editing existing mailservers

Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrea Maria Piana 2018-05-30 14:11:30 +02:00
parent e59ffc905d
commit 1e4311d4cb
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
6 changed files with 246 additions and 68 deletions

View File

@ -0,0 +1,22 @@
(ns status-im.models.wnode
(:require
[clojure.string :as string]
[status-im.utils.ethereum.core :as ethereum]))
(defn- extract-address-components [address]
(rest (re-matches #"enode://(.*)@(.*)" address)))
(defn- get-chain [db]
(let [network (get (:networks (:account/account db)) (:network db))]
(ethereum/network->chain-keyword network)))
(defn get-wnode [wnode-id {:keys [db]}]
(get-in db [:inbox/wnodes (get-chain db) wnode-id]))
(defn current-wnode? [wnode-id {:keys [db]}]
(let [current-wnode-id (get-in db [:account/account :settings :wnode (get-chain db)])]
(= current-wnode-id wnode-id)))
(defn build-url [address password]
(let [[initial host] (extract-address-components address)]
(str "enode://" initial ":" password "@" host)))

View File

@ -1,6 +1,7 @@
(ns status-im.ui.screens.offline-messaging-settings.edit-mailserver.events (ns status-im.ui.screens.offline-messaging-settings.edit-mailserver.events
(:require [clojure.string :as string] (:require [clojure.string :as string]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.models.wnode :as models.wnode]
[status-im.utils.handlers :refer [register-handler] :as handlers] [status-im.utils.handlers :refer [register-handler] :as handlers]
[status-im.utils.handlers-macro :as handlers-macro] [status-im.utils.handlers-macro :as handlers-macro]
[status-im.ui.screens.accounts.utils :as accounts.utils] [status-im.ui.screens.accounts.utils :as accounts.utils]
@ -9,38 +10,57 @@
[status-im.utils.inbox :as utils.inbox] [status-im.utils.inbox :as utils.inbox]
[status-im.data-store.mailservers :as data-store.mailservers])) [status-im.data-store.mailservers :as data-store.mailservers]))
(defn- new-mailserver [id mailserver-name address] (defn- build-mailserver [id mailserver-name address]
(assoc (utils.inbox/address->mailserver address) (assoc (utils.inbox/address->mailserver address)
:id (string/replace id "-" "") :id (string/replace id "-" "")
:name mailserver-name)) :name mailserver-name))
(defn save-new-mailserver [{{:mailservers/keys [manage] :account/keys [account] :as db} :db :as cofx} _] (defn upsert-mailserver [{{:mailservers/keys [manage] :account/keys [account] :as db} :db :as cofx} _]
(let [{:keys [name url]} manage (let [{:keys [name url id]} manage
network (get (:networks (:account/account db)) (:network db)) network (get (:networks (:account/account db)) (:network db))
chain (ethereum/network->chain-keyword network) chain (ethereum/network->chain-keyword network)
mailserver (new-mailserver mailserver (build-mailserver
(string/replace (:random-id cofx) "-" "") (or (:value id)
(:value name) (string/replace (:random-id cofx) "-" ""))
(:value url))] (:value name)
(:value url))
connected-to-wnode? (models.wnode/current-wnode? (:id mailserver) cofx)]
{:db (-> db {:db (-> db
(dissoc :mailservers/manage) (dissoc :mailservers/manage)
(assoc-in [:inbox/wnodes chain (:id mailserver)] mailserver)) (assoc-in [:inbox/wnodes chain (:id mailserver)] mailserver))
:data-store/tx [(data-store.mailservers/save-mailserver-tx (assoc :data-store/tx [{:transaction
mailserver (data-store.mailservers/save-mailserver-tx (assoc
:chain mailserver
chain))] :chain
chain))
;; we naively logout if the user is connected to the edited mailserver
:success-event (when connected-to-wnode? [:logout])}]
:dispatch [:navigate-back]})) :dispatch [:navigate-back]}))
(defn set-input [input-key value {:keys [db]}] (defn set-input [input-key value {:keys [db]}]
{:db (update db :mailservers/manage assoc input-key {:value value {:db (update db :mailservers/manage assoc input-key {:value value
:error (if (= input-key :name) :error (case input-key
(string/blank? value) :id false
(not (utils.inbox/valid-enode-address? value)))})}) :name (string/blank? value)
:url (not (utils.inbox/valid-enode-address? value)))})})
(defn edit-mailserver [wnode-id {:keys [db] :as cofx}]
(let [{:keys [id
address
password
name]} (models.wnode/get-wnode wnode-id cofx)
url (when address (models.wnode/build-url address password))
fxs (handlers-macro/merge-fx
cofx
(set-input :id id)
(set-input :url (str url))
(set-input :name (str name)))]
(assoc fxs :dispatch [:navigate-to :edit-mailserver])))
(handlers/register-handler-fx (handlers/register-handler-fx
:save-new-mailserver :upsert-mailserver
[(re-frame/inject-cofx :random-id)] [(re-frame/inject-cofx :random-id)]
save-new-mailserver) upsert-mailserver)
(handlers/register-handler-fx (handlers/register-handler-fx
:mailserver-set-input :mailserver-set-input
@ -49,11 +69,8 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:edit-mailserver :edit-mailserver
(fn [{db :db} _] (fn [cofx [_ wnode-id]]
{:db (update-in db [:mailservers/manage] assoc (edit-mailserver wnode-id cofx)))
:name {:error true}
:url {:error true})
:dispatch [:navigate-to :edit-mailserver]}))
(handlers/register-handler-fx (handlers/register-handler-fx
:set-mailserver-from-qr :set-mailserver-from-qr

View File

@ -1,6 +1,7 @@
(ns status-im.ui.screens.offline-messaging-settings.edit-mailserver.styles (ns status-im.ui.screens.offline-messaging-settings.edit-mailserver.styles
(:require-macros [status-im.utils.styles :refer [defstyle]]) (:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.ui.components.styles :as styles])) (:require [status-im.ui.components.styles :as styles]
[status-im.ui.components.colors :as colors]))
(def edit-mailserver-view (def edit-mailserver-view
{:flex 1 {:flex 1
@ -28,3 +29,31 @@
{:flex-direction :row {:flex-direction :row
:margin-horizontal 12 :margin-horizontal 12
:margin-vertical 15}) :margin-vertical 15})
(def connect-button-container
{:margin-top 8
:margin-bottom 16
:margin-horizontal 16})
(defstyle connect-button
{:height 52
:align-items :center
:justify-content :center
:background-color colors/blue
:border-radius 8
:ios {:opacity 0.9}})
(defstyle connect-button-label
{:color colors/white
:ios {:font-size 17
:letter-spacing -0.2}
:android {:font-size 14}})
(defstyle connect-button-description
{:color colors/gray
:ios {:margin-top 8
:height 20
:font-size 14
:letter-spacing -0.2}
:android {:margin-top 12
:font-size 12}})

View File

@ -14,6 +14,15 @@
[status-im.ui.components.text-input.view :as text-input] [status-im.ui.components.text-input.view :as text-input]
[status-im.ui.screens.offline-messaging-settings.edit-mailserver.styles :as styles])) [status-im.ui.screens.offline-messaging-settings.edit-mailserver.styles :as styles]))
(defn connect-button [id]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:connect-wnode id])}
[react/view styles/connect-button-container
[react/view {:style styles/connect-button
:accessibility-label :mailserver-connect-button}
[react/text {:style styles/connect-button-label
:uppercase? true}
(i18n/label :t/connect)]]]])
(def qr-code (def qr-code
[react/touchable-highlight {:on-press #(re-frame/dispatch [:scan-qr-code [react/touchable-highlight {:on-press #(re-frame/dispatch [:scan-qr-code
{:toolbar-title (i18n/label :t/add-mailserver)} {:toolbar-title (i18n/label :t/add-mailserver)}
@ -25,32 +34,36 @@
(views/defview edit-mailserver [] (views/defview edit-mailserver []
(views/letsubs [manage-mailserver [:get-manage-mailserver] (views/letsubs [manage-mailserver [:get-manage-mailserver]
is-valid? [:manage-mailserver-valid?]] is-valid? [:manage-mailserver-valid?]]
[react/view components.styles/flex (let [url (get-in manage-mailserver [:url :value])
[status-bar/status-bar] id (get-in manage-mailserver [:id :value])
[react/keyboard-avoiding-view components.styles/flex name (get-in manage-mailserver [:name :value])]
[toolbar/simple-toolbar (i18n/label :t/add-mailserver)] [react/view components.styles/flex
[react/scroll-view [status-bar/status-bar]
[react/view styles/edit-mailserver-view [react/keyboard-avoiding-view components.styles/flex
[text-input/text-input-with-label [toolbar/simple-toolbar (i18n/label :t/add-mailserver)]
{:label (i18n/label :t/name) [react/scroll-view
:placeholder (i18n/label :t/specify-name) [react/view styles/edit-mailserver-view
:style styles/input [text-input/text-input-with-label
:container styles/input-container {:label (i18n/label :t/name)
:default-value (get-in manage-mailserver [:name :value]) :placeholder (i18n/label :t/specify-name)
:on-change-text #(re-frame/dispatch [:mailserver-set-input :name %]) :style styles/input
:auto-focus true}] :container styles/input-container
[text-input/text-input-with-label :default-value name
{:label (i18n/label :t/mailserver-address) :on-change-text #(re-frame/dispatch [:mailserver-set-input :name %])
:placeholder (i18n/label :t/specify-mailserver-address) :auto-focus true}]
:content qr-code [text-input/text-input-with-label
:style styles/input {:label (i18n/label :t/mailserver-address)
:container styles/input-container :placeholder (i18n/label :t/specify-mailserver-address)
:default-value (get-in manage-mailserver [:url :value]) :content qr-code
:on-change-text #(re-frame/dispatch [:mailserver-set-input :url %])}]]] :style styles/input
[react/view styles/bottom-container :container styles/input-container
[react/view components.styles/flex] :default-value url
[components.common/bottom-button :on-change-text #(re-frame/dispatch [:mailserver-set-input :url %])}]
{:forward? true (when id [connect-button id])]]
:label (i18n/label :t/save) [react/view styles/bottom-container
:disabled? (not is-valid?) [react/view components.styles/flex]
:on-press #(re-frame/dispatch [:save-new-mailserver])}]]]])) [components.common/bottom-button
{:forward? true
:label (i18n/label :t/save)
:disabled? (not is-valid?)
:on-press #(re-frame/dispatch [:upsert-mailserver])}]]]])))

View File

@ -15,14 +15,19 @@
[react/view (styles/wnode-icon connected?) [react/view (styles/wnode-icon connected?)
[vector-icons/icon :icons/wnode {:color (if connected? :white :gray)}]]) [vector-icons/icon :icons/wnode {:color (if connected? :white :gray)}]])
(defn navigate-to-add-mailserver [] (defn connect-to-mailserver [id]
(re-frame/dispatch [:edit-mailserver])) (re-frame/dispatch [:connect-wnode id]))
(defn- render-row [current-wnode] (defn navigate-to-add-mailserver [wnode-id]
(fn [{:keys [name id]}] (re-frame/dispatch [:edit-mailserver wnode-id]))
(let [connected? (= id current-wnode)]
(defn- render-row [current-wnode-id]
(fn [{:keys [name id user-defined]}]
(let [connected? (= id current-wnode-id)]
[react/touchable-highlight [react/touchable-highlight
{:on-press #(re-frame/dispatch [:connect-wnode id]) {:on-press #(if user-defined
(navigate-to-add-mailserver id)
(connect-to-mailserver id))
:accessibility-label :mailserver-item} :accessibility-label :mailserver-item}
[react/view styles/wnode-item [react/view styles/wnode-item
[wnode-icon connected?] [wnode-icon connected?]
@ -31,8 +36,8 @@
name]]]]))) name]]]])))
(views/defview offline-messaging-settings [] (views/defview offline-messaging-settings []
(views/letsubs [current-wnode [:settings/current-wnode] (views/letsubs [current-wnode-id [:settings/current-wnode]
wnodes [:settings/network-wnodes]] wnodes [:settings/network-wnodes]]
[react/view {:flex 1} [react/view {:flex 1}
[status-bar/status-bar] [status-bar/status-bar]
[toolbar/toolbar {} [toolbar/toolbar {}
@ -40,9 +45,9 @@
[toolbar/content-title (i18n/label :t/offline-messaging-settings)] [toolbar/content-title (i18n/label :t/offline-messaging-settings)]
(when config/add-custom-mailservers-enabled? (when config/add-custom-mailservers-enabled?
[toolbar/actions [toolbar/actions
[(toolbar.actions/add false navigate-to-add-mailserver)]])] [(toolbar.actions/add false (partial navigate-to-add-mailserver nil))]])]
[react/view styles/wrapper [react/view styles/wrapper
[list/flat-list {:data (vals wnodes) [list/flat-list {:data (vals wnodes)
:default-separator? false :default-separator? false
:key-fn :id :key-fn :id
:render-fn (render-row current-wnode)}]]])) :render-fn (render-row current-wnode-id)}]]]))

View File

@ -2,7 +2,12 @@
(:require [cljs.test :refer-macros [deftest is testing]] (:require [cljs.test :refer-macros [deftest is testing]]
[status-im.ui.screens.offline-messaging-settings.edit-mailserver.events :as events])) [status-im.ui.screens.offline-messaging-settings.edit-mailserver.events :as events]))
(def valid-enode-url "enode://1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40:somepassword@167.99.209.61:30504") (def enode-id "1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40")
(def password "password")
(def host "167.99.209.61:30504")
(def valid-enode-address (str "enode://" enode-id "@" host))
(def valid-enode-url (str "enode://" enode-id ":" password "@" host))
(deftest set-input (deftest set-input
(testing "it validates names" (testing "it validates names"
@ -24,8 +29,59 @@
:error true}}}} :error true}}}}
(events/set-input :url "broken" {})))))) (events/set-input :url "broken" {}))))))
(deftest save-new-mailserver (deftest edit-mailserver
(testing "save a new mailserver" (let [db {:network "mainnet_rpc"
:account/account {:networks {"mainnet_rpc"
{:config {:NetworkId 1}}}}
:inbox/wnodes
{:mainnet {"a" {:id "a"
:address valid-enode-address
:password password
:name "name"}}}}
cofx {:db db}]
(testing "when no id is given"
(let [actual (events/edit-mailserver nil cofx)]
(testing "it resets :mailserver/manage"
(is (= {:id {:value nil
:error false}
:url {:value ""
:error true}
:name {:value ""
:error true}}
(-> actual :db :mailservers/manage))))
(testing "it navigates to edit-mailserver view"
(is (= [:navigate-to :edit-mailserver]
(-> actual :dispatch))))))
(testing "when an id is given"
(testing "when the wnode is in the list"
(let [actual (events/edit-mailserver "a" cofx)]
(testing "it populates the fields with the correct values"
(is (= {:id {:value "a"
:error false}
:url {:value valid-enode-url
:error false}
:name {:value "name"
:error false}}
(-> actual :db :mailservers/manage))))
(testing "it navigates to edit-mailserver view"
(is (= [:navigate-to :edit-mailserver]
(-> actual :dispatch))))))
(testing "when the wnode is not in the list"
(let [actual (events/edit-mailserver "not-existing" cofx)]
(testing "it populates the fields with the correct values"
(is (= {:id {:value nil
:error false}
:url {:value ""
:error true}
:name {:value ""
:error true}}
(-> actual :db :mailservers/manage))))
(testing "it navigates to edit-mailserver view"
(is (= [:navigate-to :edit-mailserver]
(-> actual :dispatch)))))))))
(deftest upsert-mailserver
(testing "new mailserver"
(let [cofx {:random-id "random-id" (let [cofx {:random-id "random-id"
:db {:network "mainnet_rpc" :db {:network "mainnet_rpc"
:account/account {:networks {"mainnet_rpc" :account/account {:networks {"mainnet_rpc"
@ -34,7 +90,8 @@
:url {:value "enode://test-id:test-password@url:port"}} :url {:value "enode://test-id:test-password@url:port"}}
:inbox/wnodes {}}} :inbox/wnodes {}}}
actual (events/save-new-mailserver cofx nil)] actual (events/upsert-mailserver cofx nil)]
(testing "it adds the enode to inbox/wnodes" (testing "it adds the enode to inbox/wnodes"
(is (= {:mainnet {"randomid" {:password "test-password" (is (= {:mainnet {"randomid" {:password "test-password"
:address "enode://test-id@url:port" :address "enode://test-id@url:port"
@ -42,5 +99,40 @@
:id "randomid" :id "randomid"
:user-defined true}}} :user-defined true}}}
(get-in actual [:db :inbox/wnodes])))) (get-in actual [:db :inbox/wnodes]))))
(testing "it navigates back"
(is (= [:navigate-back]
(:dispatch actual))))
(testing "it stores it in the db" (testing "it stores it in the db"
(is (= 1 (count (:data-store/tx actual)))))))) (is (= 1 (count (:data-store/tx actual)))))))
(testing "existing mailserver"
(let [cofx {:random-id "random-id"
:db {:network "mainnet_rpc"
:account/account {:networks {"mainnet_rpc"
{:config {:NetworkId 1}}}}
:mailservers/manage {:id {:value "a"}
:name {:value "new-name"}
:url {:value "enode://new-id:new-password@url:port"}}
:inbox/wnodes {:mainnet {"a" {:id "a"
:name "old-name"
:address "enode://old-id:old-password@url:port"}}}}}
actual (events/upsert-mailserver cofx nil)]
(testing "it navigates back"
(is (= [:navigate-back]
(:dispatch actual))))
(testing "it updates the enode to inbox/wnodes"
(is (= {:mainnet {"a" {:password "new-password"
:address "enode://new-id@url:port"
:name "new-name"
:id "a"
:user-defined true}}}
(get-in actual [:db :inbox/wnodes]))))
(testing "it stores it in the db"
(is (= 1 (count (:data-store/tx actual)))))
(testing "it logs the user out if connected to the current mailserver"
(let [actual (events/upsert-mailserver (assoc-in cofx
[:db :account/account :settings]
{:wnode
{:mainnet "a"}}) nil)]
(is (= [:logout]
(-> actual :data-store/tx first :success-event))))))))