diff --git a/src/status_im/models/network.cljs b/src/status_im/models/network.cljs new file mode 100644 index 0000000000..7332b44bf2 --- /dev/null +++ b/src/status_im/models/network.cljs @@ -0,0 +1,66 @@ +(ns status-im.models.network + (:require [clojure.string :as string] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.handlers-macro :as handlers-macro] + [status-im.ui.screens.accounts.utils :as accounts.utils])) + +(def url-regex + #"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)") + +(defn valid-rpc-url? [url] + (boolean (re-matches url-regex (str url)))) + +(def default-manage + {:name {:value ""} + :url {:value ""} + :chain {:value :mainnet}}) + +(defn validate-string [{:keys [value]}] + {:value value + :error (string/blank? value)}) + +(defn validate-url [{:keys [value]}] + {:value value + :error (not (valid-rpc-url? value))}) + +(defn validate-manage [manage] + (-> manage + (update :url validate-url) + (update :name validate-string) + (update :chain validate-string))) + +(defn valid-manage? [manage] + (->> (validate-manage manage) + vals + (map :error) + (not-any? identity))) + +(defn- new-network [{:keys [random-id] :as cofx} network-name upstream-url type] + (let [data-dir (str "/ethereum/" (name type) "_rpc") + config {:NetworkId (ethereum/chain-keyword->chain-id type) + :DataDir data-dir + :UpstreamConfig {:Enabled true + :URL upstream-url}}] + {:id (string/replace random-id "-" "") + :name network-name + :config config})) + +(defn set-input [input-key value {:keys [db]}] + {:db (-> db + (update-in [:networks/manage input-key] assoc :value value) + (update-in [:networks/manage] validate-manage))}) + +(defn save [{{:networks/keys [manage] :account/keys [account] :as db} :db :as cofx}] + (when (valid-manage? manage) + (let [{:keys [name url chain]} manage + network (new-network cofx (:value name) (:value url) (:value chain)) + new-networks (merge {(:id network) network} (:networks account))] + (handlers-macro/merge-fx cofx + {:db (dissoc db :networks/manage) + :dispatch [:navigate-back]} + (accounts.utils/account-update {:networks new-networks}))))) + +;; No edit functionality actually implemented +(defn edit [{db :db}] + {:db (assoc db :networks/manage (validate-manage default-manage)) + :dispatch [:navigate-to :edit-network]}) diff --git a/src/status_im/ui/screens/network_settings/edit_network/events.cljs b/src/status_im/ui/screens/network_settings/edit_network/events.cljs index 6aec6b5eb9..dab316e4da 100644 --- a/src/status_im/ui/screens/network_settings/edit_network/events.cljs +++ b/src/status_im/ui/screens/network_settings/edit_network/events.cljs @@ -1,46 +1,20 @@ (ns status-im.ui.screens.network-settings.edit-network.events (:require [re-frame.core :as re-frame] - [status-im.utils.handlers :refer [register-handler] :as handlers] - [status-im.utils.handlers-macro :as handlers-macro] - [status-im.ui.screens.accounts.utils :as accounts.utils] - [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.types :as types] - [clojure.string :as string])) - -(defn- new-network [{:keys [random-id] :as cofx} network-name upstream-url type] - (let [data-dir (str "/ethereum/" (name type) "_rpc") - config {:NetworkId (ethereum/chain-keyword->chain-id type) - :DataDir data-dir - :UpstreamConfig {:Enabled true - :URL upstream-url}}] - {:id (string/replace random-id "-" "") - :name network-name - :config config})) + [status-im.models.network :as models.network] + [status-im.utils.handlers :refer [register-handler] :as handlers])) (handlers/register-handler-fx :save-new-network [(re-frame/inject-cofx :random-id)] - (fn [{{:networks/keys [manage] :account/keys [account] :as db} :db :as cofx} _] - (let [{:keys [name url chain]} manage - network (new-network cofx (:value name) (:value url) (:value chain)) - new-networks (merge {(:id network) network} (:networks account))] - (handlers-macro/merge-fx cofx - {:db (dissoc db :networks/manage) - :dispatch [:navigate-back]} - (accounts.utils/account-update {:networks new-networks}))))) + (fn [cofx _] + (models.network/save cofx))) (handlers/register-handler-fx :network-set-input - (fn [{db :db} [_ input-key value]] - {:db (update db :networks/manage merge {input-key {:value value - :error (and (string? value) (empty? value))}})})) + (fn [cofx [_ input-key value]] + (models.network/set-input input-key value cofx))) (handlers/register-handler-fx :edit-network - (fn [{db :db} _] - {:db (update-in db [:networks/manage] assoc - :name {:error true} - :url {:error true} - :chain {:value :mainnet}) - :dispatch [:navigate-to :edit-network]})) - + (fn [cofx _] + (models.network/edit cofx))) diff --git a/test/cljs/status_im/test/models/network.cljs b/test/cljs/status_im/test/models/network.cljs new file mode 100644 index 0000000000..063c4f3704 --- /dev/null +++ b/test/cljs/status_im/test/models/network.cljs @@ -0,0 +1,86 @@ +(ns status-im.test.models.network + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.models.network :as model])) + +(deftest valid-rpc-url-test + (testing "nil?" + (is (not (model/valid-rpc-url? nil)))) + (testing "a blank url" + (is (not (model/valid-rpc-url? "")))) + (testing "a url without a protocol" + (is (not (model/valid-rpc-url? "something")))) + (testing "a url without a protocol" + (is (not (model/valid-rpc-url? "http://something with space")))) + (testing "a url without a hostname" + (is (not (model/valid-rpc-url? "https://")))) + (testing "an http url" + (is (model/valid-rpc-url? "http://valid.com"))) + (testing "an https url" + (is (model/valid-rpc-url? "https://valid.something.else"))) + (testing "a fully qualified url" + (is (model/valid-rpc-url? "https://mainnet.infura.io:6523/z6GCTmjdP3FETEJmMBI4"))) + (testing "an ip address" + (is (model/valid-rpc-url? "https://192.168.1.1"))) + (testing "localhost" + (is (model/valid-rpc-url? "https://localhost"))) + (testing "a fully qualified url, ip address" + (is (model/valid-rpc-url? "https://192.168.1.1:6523/z6GCTmjdP3FETEJmMBI4"))) + (testing "an https url not on the default port" + (is (model/valid-rpc-url? "https://valid.something.else:65323")))) + +(deftest new-network-test + (let [actual (model/new-network {:random-id "random-id"} + "network-name" + "upstream-url" + :mainnet)] + (is (= {:id "randomid" + :name "network-name" + :config {:NetworkId 1 + :DataDir "/ethereum/mainnet_rpc" + :UpstreamConfig {:Enabled true + :URL "upstream-url"}}} + actual)))) + +(deftest valid-manage-test + (testing "a valid manage" + (is (model/valid-manage? {:url {:value "http://valid.com"} + :name {:value "valid"} + :chain {:value "valid"}}))) + (testing "invalid url" + (is (not (model/valid-manage? {:url {:value "invalid"} + :name {:value "valid"} + :chain {:value "valid"}})))) + + (testing "invalid name" + (is (not (model/valid-manage? {:url {:value "http://valid.com"} + :name {:value ""} + :chain {:value "valid"}})))) + + (testing "invalid chain" + (is (not (model/valid-manage? {:url {:value "http://valid.com"} + :name {:value "valid"} + :chain {:value ""}}))))) + +(deftest set-input-test + (testing "it updates and validate a field" + (is (= {:db {:networks/manage {:url {:value "http://valid.com" + :error false} + :name {:value "" + :error true} + :chain {:value "mainnet" + :error false}}}} + (model/set-input :url "http://valid.com" + {:db {:networks/manage {:url {:value "something" + :error true} + :name {:value "" + :error false} + :chain {:value "mainnet" + :error false}}}}))))) + +(deftest save + (testing "it does not save a network with an invalid url" + (is (nil? (model/save {:random-id "random" + :db {:networks/manage {:url {:value "wrong"} + :chain {:value "1"} + :name {:value "empty"}} + :account/account {}}}))))) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index 595c2ec0ea..05321c4e01 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -14,6 +14,7 @@ [status-im.test.models.bootnode] [status-im.test.models.account] [status-im.test.models.contact] + [status-im.test.models.network] [status-im.test.transport.core] [status-im.test.transport.inbox] [status-im.test.transport.handlers] @@ -39,7 +40,6 @@ [status-im.test.utils.datetime] [status-im.test.utils.mixpanel] [status-im.test.utils.prices] - [status-im.test.ui.screens.network-settings.edit-network.events] [status-im.test.ui.screens.accounts.login.events])) (enable-console-print!) @@ -64,6 +64,7 @@ 'status-im.test.models.bootnode 'status-im.test.models.account 'status-im.test.models.contact + 'status-im.test.models.network 'status-im.test.bots.events 'status-im.test.wallet.subs 'status-im.test.wallet.transactions.subs @@ -90,5 +91,4 @@ 'status-im.test.utils.datetime 'status-im.test.utils.mixpanel 'status-im.test.utils.prices - 'status-im.test.ui.screens.network-settings.edit-network.events 'status-im.test.ui.screens.accounts.login.events) diff --git a/test/cljs/status_im/test/ui/screens/network_settings/edit_network/events.cljs b/test/cljs/status_im/test/ui/screens/network_settings/edit_network/events.cljs deleted file mode 100644 index 67c00de802..0000000000 --- a/test/cljs/status_im/test/ui/screens/network_settings/edit_network/events.cljs +++ /dev/null @@ -1,16 +0,0 @@ -(ns status-im.test.ui.screens.network-settings.edit-network.events - (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.ui.screens.network-settings.edit-network.events :as events])) - -(deftest new-network - (let [actual (events/new-network {:random-id "random-id"} - "network-name" - "upstream-url" - :mainnet)] - (is (= {:id "randomid" - :name "network-name" - :config {:NetworkId 1 - :DataDir "/ethereum/mainnet_rpc" - :UpstreamConfig {:Enabled true - :URL "upstream-url"}}} - actual))))