From 49592f3a50c4e5209c8c5ae5982feca9d8588a48 Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Fri, 1 Jun 2018 14:32:37 +0200 Subject: [PATCH] Allow editing/deleting custom bootnodes Signed-off-by: Andrea Maria Piana --- src/status_im/models/bootnode.cljs | 44 ++++++++---- src/status_im/translations/en.cljs | 5 ++ .../edit_bootnode/events.cljs | 8 ++- .../edit_bootnode/styles.cljs | 22 ++++++ .../edit_bootnode/views.cljs | 23 +++++- .../ui/screens/bootnodes_settings/views.cljs | 11 +-- .../edit_mailserver/views.cljs | 2 +- test/cljs/status_im/test/models/bootnode.cljs | 71 ++++++++++++++++++- 8 files changed, 161 insertions(+), 25 deletions(-) diff --git a/src/status_im/models/bootnode.cljs b/src/status_im/models/bootnode.cljs index 2c8bb92318..85e42d1e9e 100644 --- a/src/status_im/models/bootnode.cljs +++ b/src/status_im/models/bootnode.cljs @@ -43,21 +43,39 @@ (set-input :name (str name)))] (assoc fxs :dispatch [:navigate-to :edit-bootnode]))) -(defn save [{{:bootnodes/keys [manage] :account/keys [account] :as db} :db :as cofx}] - (let [{:keys [name url]} manage - network (:network db) - bootnode (build - (:random-id cofx) - (:value name) - (:value url) - network) - new-bootnodes (assoc-in - (:bootnodes account) - [network (:id bootnode)] - bootnode)] +(defn custom-bootnodes-in-use? [{:keys [db] :as cofx}] + (let [network (:network db)] + (get-in db [:account/account :settings :bootnodes network]))) + +(defn delete [id {{:account/keys [account] :as db} :db :as cofx}] + (let [network (:network db) + new-account (update-in account [:bootnodes network] dissoc id)] + (handlers-macro/merge-fx {:db (assoc db :account/account new-account)} + (accounts.utils/account-update + (select-keys new-account [:bootnodes]) + (when (custom-bootnodes-in-use? cofx) + [:logout]))))) + +(defn upsert [{{:bootnodes/keys [manage] :account/keys [account] :as db} :db :as cofx}] + (let [{:keys [name + id + url]} manage + network (:network db) + bootnode (build + (or (:value id) (:random-id cofx)) + (:value name) + (:value url) + network) + new-bootnodes (assoc-in + (:bootnodes account) + [network (:id bootnode)] + bootnode)] (handlers-macro/merge-fx cofx {:db (dissoc db :bootnodes/manage) :dispatch [:navigate-back]} - (accounts.utils/account-update {:bootnodes new-bootnodes})))) + (accounts.utils/account-update + {:bootnodes new-bootnodes} + (when (custom-bootnodes-in-use? cofx) + [:logout]))))) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 7da688e91e..c3f86a5f63 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -597,6 +597,7 @@ ;; TODO(dmitryn): come up with better description/naming. Suggested namings: Mailbox and Master Node :existing-wnodes "Existing mailservers" :add-mailserver "Add Mailserver" + :mailserver-details "Mailserver details" :delete-mailserver-title "Delete mailserver" :delete-mailserver-are-you-sure "Are you sure you want to delete this mailserver?" :delete-mailserver "Delete mailserver" @@ -632,7 +633,11 @@ :bootnodes-enabled "Bootnodes enabled" :bootnode-address "Bootnode address" :add-bootnode "Add bootnode" + :bootnode-details "Bootnode details" :specify-bootnode-address "Specify bootnode address" + :delete-bootnode-title "Delete bootnode" + :delete-bootnode-are-you-sure "Are you sure you want to delete this bootnode?" + :delete-bootnode "Delete bootnode" :mainnet-warning-title "Warning!" :mainnet-warning-text "While we highly appreciate your contribution as a tester of Status, we’d like to point out the dangers. You’re switching to Mainnet mode which is still in Alpha. This means it is still in development and has not been audited yet. Some of the risks you may be exposed to include:\n\n- Accounts may be unrecoverable due to breaking changes\n- Loss of ETH and tokens\n- Failure to send or receive messages\n\nSwitching to Mainnet should be done for testing purposes only. By tapping \"I understand\", you confirm that you assume the full responsibility for all risks concerning your data and funds. " diff --git a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/events.cljs b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/events.cljs index 372a5bb5b7..8fa6bf45d8 100644 --- a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/events.cljs +++ b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/events.cljs @@ -8,7 +8,7 @@ :save-new-bootnode [(re-frame/inject-cofx :random-id)] (fn [cofx _] - (models.bootnode/save cofx))) + (models.bootnode/upsert cofx))) (handlers/register-handler-fx :bootnode-set-input @@ -20,6 +20,12 @@ (fn [cofx [_ bootnode-id]] (models.bootnode/edit bootnode-id cofx))) +(handlers/register-handler-fx + :delete-bootnode + (fn [cofx [_ bootnode-id]] + (assoc (models.bootnode/delete bootnode-id cofx) + :dispatch [:navigate-back]))) + (handlers/register-handler-fx :set-bootnode-from-qr (fn [cofx [_ _ url]] diff --git a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/styles.cljs b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/styles.cljs index 3a5c8be3cd..14ae4cb176 100644 --- a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/styles.cljs +++ b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/styles.cljs @@ -29,3 +29,25 @@ {:flex-direction :row :margin-horizontal 12 :margin-vertical 15}) + +(def button-container + {:margin-top 8 + :margin-bottom 16 + :margin-horizontal 16}) + +(def button + {:height 52 + :align-items :center + :justify-content :center + :border-radius 8 + :ios {:opacity 0.9}}) + +(defstyle button-label + {:color colors/white + :ios {:font-size 17 + :letter-spacing -0.2} + :android {:font-size 14}}) + +(defstyle delete-button + (assoc button + :background-color colors/red)) diff --git a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs index cc8458b72c..2932156b42 100644 --- a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs +++ b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs @@ -4,6 +4,7 @@ [re-frame.core :as re-frame] [status-im.ui.components.react :as react] [status-im.i18n :as i18n] + [status-im.utils.utils :as utils] [status-im.ui.components.styles :as components.styles] [status-im.ui.components.common.common :as components.common] [status-im.ui.components.colors :as colors] @@ -13,6 +14,21 @@ [status-im.ui.components.text-input.view :as text-input] [status-im.ui.screens.bootnodes-settings.edit-bootnode.styles :as styles])) +(defn handle-delete [id] + (utils/show-confirmation (i18n/label :t/delete-bootnode-title) + (i18n/label :t/delete-bootnode-are-you-sure) + (i18n/label :t/delete-bootnode) + #(re-frame/dispatch [:delete-bootnode id]))) + +(defn delete-button [id] + [react/touchable-highlight {:on-press #(handle-delete id)} + [react/view styles/button-container + [react/view {:style styles/delete-button + :accessibility-label :bootnode-delete-button} + [react/text {:style styles/button-label + :uppercase? true} + (i18n/label :t/delete)]]]]) + (def qr-code [react/touchable-highlight {:on-press #(re-frame/dispatch [:scan-qr-code {:toolbar-title (i18n/label :t/add-bootnode)} @@ -25,12 +41,13 @@ (views/letsubs [manage-bootnode [:get-manage-bootnode] is-valid? [:manage-bootnode-valid?]] (let [url (get-in manage-bootnode [:url :value]) + id (get-in manage-bootnode [:id :value]) name (get-in manage-bootnode [:name :value])] [react/view components.styles/flex [status-bar/status-bar] [react/keyboard-avoiding-view components.styles/flex - [toolbar/simple-toolbar (i18n/label :t/add-bootnode)] + [toolbar/simple-toolbar (i18n/label (if id :t/bootnode-details :t/add-bootnode))] [react/scroll-view [react/view styles/edit-bootnode-view [text-input/text-input-with-label @@ -48,7 +65,9 @@ :style styles/input :container styles/input-container :default-value url - :on-change-text #(re-frame/dispatch [:bootnode-set-input :url %])}]]] + :on-change-text #(re-frame/dispatch [:bootnode-set-input :url %])}] + (when id + [delete-button id])]] [react/view styles/bottom-container [react/view components.styles/flex] [components.common/bottom-button diff --git a/src/status_im/ui/screens/bootnodes_settings/views.cljs b/src/status_im/ui/screens/bootnodes_settings/views.cljs index ed603601fd..5f32510d54 100644 --- a/src/status_im/ui/screens/bootnodes_settings/views.cljs +++ b/src/status_im/ui/screens/bootnodes_settings/views.cljs @@ -13,12 +13,13 @@ [status-im.ui.screens.profile.components.views :as profile.components] [status-im.ui.screens.bootnodes-settings.styles :as styles])) -(defn navigate-to-add-bootnode [] - (re-frame/dispatch [:edit-bootnode])) +(defn navigate-to-add-bootnode [id] + (re-frame/dispatch [:edit-bootnode id])) (defn render-row [{:keys [name id]}] - [react/view - {:accessibility-label :bootnode-item} + [react/touchable-highlight + {:on-press #(navigate-to-add-bootnode id) + :accessibility-label :bootnode-item} [react/view styles/bootnode-item [react/view styles/bootnode-item-inner [react/text {:style styles/bootnode-item-name-text} @@ -33,7 +34,7 @@ toolbar/default-nav-back [toolbar/content-title (i18n/label :t/bootnodes-settings)] [toolbar/actions - [(toolbar.actions/add false navigate-to-add-bootnode)]]] + [(toolbar.actions/add false #(navigate-to-add-bootnode nil))]]] [react/view styles/switch-container [profile.components/settings-switch-item {:label-kw :t/bootnodes-enabled diff --git a/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs b/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs index f45037c2fe..9cbd799544 100644 --- a/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs +++ b/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs @@ -57,7 +57,7 @@ [react/view components.styles/flex [status-bar/status-bar] [react/keyboard-avoiding-view components.styles/flex - [toolbar/simple-toolbar (i18n/label :t/add-mailserver)] + [toolbar/simple-toolbar (i18n/label (if id :t/mailserver-details :t/add-mailserver))] [react/scroll-view [react/view styles/edit-mailserver-view [text-input/text-input-with-label diff --git a/test/cljs/status_im/test/models/bootnode.cljs b/test/cljs/status_im/test/models/bootnode.cljs index 00f082d8ca..dcd5fc7be4 100644 --- a/test/cljs/status_im/test/models/bootnode.cljs +++ b/test/cljs/status_im/test/models/bootnode.cljs @@ -7,19 +7,38 @@ (def valid-bootnode-address (str "enode://" bootnode-id "@" host)) -(deftest save-bootnode - (testing "adding a bootnode" +(deftest upsert-bootnode + (testing "adding a new bootnode" (let [new-bootnode {:name {:value "name"} :url {:value "url"}} expected {"mainnet_rpc" {"someid" {:name "name" :address "url" :chain "mainnet_rpc" :id "someid"}}} - actual (model/save + actual (model/upsert {:random-id "some-id" :db {:bootnodes/manage new-bootnode :network "mainnet_rpc" :account/account {}}})] + (is (= expected (get-in actual [:db :account/account :bootnodes]))))) + (testing "adding an existing bootnode" + (let [new-bootnode {:id {:value "a"} + :name {:value "new-name"} + :url {:value "new-url"}} + expected {"mainnet_rpc" {"a" {:name "new-name" + :address "new-url" + :chain "mainnet_rpc" + :id "a"}}} + actual (model/upsert + {:random-id "some-id" + :db {:bootnodes/manage new-bootnode + :network "mainnet_rpc" + :account/account {:bootnodes + {"mainnet_rpc" + {"a" {:name "name" + :address "url" + :chain "mainnet_rpc" + :id "a"}}}}}})] (is (= expected (get-in actual [:db :account/account :bootnodes])))))) (deftest set-input-bootnode @@ -100,3 +119,49 @@ :name "name" :address "enode://old-id:old-password@url:port"}}}}}}] (is (model/fetch "a" cofx))))) + +(deftest custom-bootnodes-in-use? + (testing "is on the same network" + (testing "it returns false when not enabled" + (is (not (model/custom-bootnodes-in-use? {:db {:network "mainnet_rpc"}})))) + (testing "it returns true when enabled" + (is (model/custom-bootnodes-in-use? + {:db {:network "mainnet_rpc" + :account/account {:settings + {:bootnodes + {"mainnet_rpc" true}}}}})))) + (testing "is on a different network" + (testing "it returns false when not enabled" + (is (not (model/custom-bootnodes-in-use? {:db {:network "testnet_rpc"}})))) + (testing "it returns true when enabled" + (is (not (model/custom-bootnodes-in-use? + {:db {:network "testnet_rpc" + :account/account {:settings + {:bootnodes + {"mainnnet_rpc" true}}}}})))))) + +(deftest delete-bootnode + (testing "non existing bootnode" + (let [cofx {:db {:network "mainnet_rpc" + :account/account {:bootnodes {"mainnet_rpc" + {"a" {:id "a" + :name "name" + :address "enode://old-id:old-password@url:port"}}} + :settings {:bootnodes + {"mainnnet_rpc" true}}}}} + actual (model/delete "b" cofx)] + (testing "it does not removes the bootnode" + (is (model/fetch "a" actual))))) + (testing "existing bootnode" + (let [cofx {:db {:network "mainnet_rpc" + :account/account {:bootnodes {"mainnet_rpc" + {"a" {:id "a" + :name "name" + :address "enode://old-id:old-password@url:port"}}} + :settings {:bootnodes + {"mainnnet_rpc" true}}}}} + actual (model/delete "a" cofx)] + (testing "it removes the bootnode" + (is (not (model/fetch "a" actual)))) + (testing "it updates the db" + (is (= 1 (count (:data-store/base-tx actual))))))))