From fe9a4eac599b4b7dbcae451f0c334c34515b657f Mon Sep 17 00:00:00 2001 From: yqrashawn Date: Thu, 18 Jan 2024 22:05:31 +0800 Subject: [PATCH] feat: re-fetch community info in community overview and channel (#18465) Signed-off-by: yqrashawn --- src/legacy/status_im/events.cljs | 1 + .../ui/screens/chat/message/legacy_view.cljs | 2 +- src/status_im/common/router.cljs | 10 +- src/status_im/common/serialization.cljs | 27 ++++ src/status_im/common/universal_links.cljs | 35 +---- src/status_im/constants.cljs | 7 + .../chat/home/add_new_contact/effects.cljs | 16 +- .../chat/home/add_new_contact/events.cljs | 2 +- .../home/add_new_contact/events_test.cljs | 2 +- .../messages/link_preview/events.cljs | 92 ------------ .../messages/link_preview/events_test.cljs | 139 ------------------ .../messenger/messages/link_preview/view.cljs | 2 +- .../actions/token_gating/view.cljs | 5 +- .../contexts/communities/discover/view.cljs | 9 +- .../contexts/communities/events.cljs | 139 +++++++++++++++++- .../contexts/communities/events_test.cljs | 138 ++++++++++++++++- .../contexts/communities/home/view.cljs | 3 +- .../contexts/communities/overview/view.cljs | 8 +- .../notification/community_request/view.cljs | 2 +- .../components/switcher_cards/view.cljs | 4 +- src/status_im/subs/communities.cljs | 2 +- src/status_im/subs/root.cljs | 2 +- 22 files changed, 335 insertions(+), 312 deletions(-) create mode 100644 src/status_im/common/serialization.cljs delete mode 100644 src/status_im/contexts/chat/messenger/messages/link_preview/events_test.cljs diff --git a/src/legacy/status_im/events.cljs b/src/legacy/status_im/events.cljs index 87e8e33d472..3b778354687 100644 --- a/src/legacy/status_im/events.cljs +++ b/src/legacy/status_im/events.cljs @@ -43,6 +43,7 @@ [react-native.permissions :as permissions] [react-native.platform :as platform] [status-im.common.biometric.events :as biometric] + status-im.common.serialization status-im.common.standard-authentication.events [status-im.common.theme.core :as theme] [status-im.common.universal-links :as universal-links] diff --git a/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs b/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs index 55df7b578b9..237fcb08b40 100644 --- a/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs +++ b/src/legacy/status_im/ui/screens/chat/message/legacy_view.cljs @@ -246,7 +246,7 @@ [rn/touchable-opacity {:on-press #(do (rf/dispatch [:pop-to-root :shell-stack]) - (rf/dispatch [:navigate-to :community-overview (:id community)]) + (rf/dispatch [:communities/navigate-to-community-overview (:id community)]) (rf/dispatch [:chat/close]))} [rn/text {:style {:text-align :center diff --git a/src/status_im/common/router.cljs b/src/status_im/common/router.cljs index 653910331c9..df497c8ac0e 100644 --- a/src/status_im/common/router.cljs +++ b/src/status_im/common/router.cljs @@ -259,12 +259,6 @@ {:type :wallet-account :account (when account (string/lower-case account))}) -(defn community-route-type - [route-params] - (if (string/starts-with? (:community-id route-params) "z") - :desktop-community - :community)) - (defn handle-uri [chain chats uri cb] (let [{:keys [handler route-params query-params]} (match-uri uri)] @@ -297,14 +291,14 @@ (cb {:type handler :community-id (:community-id route-params)}) (and (= handler :community) (:community-id route-params)) - (cb {:type (community-route-type route-params) + (cb {:type :community :community-id (:community-id route-params)}) (and (= handler :community-chat) (:community-channel-id route-params) (:community-id route-params)) (match-community-channel-async route-params cb) (and (= handler :community-chat) (:community-id route-params)) - (cb {:type (community-route-type route-params) + (cb {:type :community :community-id (:community-id route-params)}) ;; NOTE: removed in `match-uri`, might need this in the future diff --git a/src/status_im/common/serialization.cljs b/src/status_im/common/serialization.cljs new file mode 100644 index 00000000000..8783008e3d2 --- /dev/null +++ b/src/status_im/common/serialization.cljs @@ -0,0 +1,27 @@ +(ns status-im.common.serialization + (:require + [native-module.core :as native-module] + [status-im.constants :as constants] + [utils.re-frame :as rf] + [utils.transforms :as transforms])) + +(rf/reg-fx :serialization/deserialize-and-compress-key + (fn [{:keys [serialized-key on-success on-error]}] + (native-module/deserialize-and-compress-key + serialized-key + (fn [resp] + (let [{:keys [error]} (transforms/json->clj resp)] + (if error + (on-error error) + (on-success resp))))))) + +(rf/reg-fx :serialization/decompress-public-key + (fn [{:keys [compressed-key on-success on-error]}] + (native-module/compressed-key->public-key + compressed-key + constants/deserialization-key + (fn [resp] + (let [{:keys [error]} (transforms/json->clj resp)] + (if error + (on-error error) + (on-success (str "0x" (subs resp 5))))))))) diff --git a/src/status_im/common/universal_links.cljs b/src/status_im/common/universal_links.cljs index 8fe8c78c99e..2324d1e34da 100644 --- a/src/status_im/common/universal_links.cljs +++ b/src/status_im/common/universal_links.cljs @@ -2,12 +2,12 @@ (:require [clojure.string :as string] [goog.string :as gstring] - [native-module.core :as native-module] [re-frame.core :as re-frame] [react-native.async-storage :as async-storage] [react-native.core :as rn] [schema.core :as schema] [status-im.constants :as constants] + [status-im.contexts.communities.events :as communities.events] [status-im.navigation.events :as navigation] [taoensso.timbre :as log] [utils.ethereum.chain :as chain] @@ -68,32 +68,6 @@ (log/info "universal-links: handling community request " community-id) (navigation/navigate-to cofx :community-requests-to-join {:community-id community-id})) -(rf/defn handle-community - [cofx {:keys [community-id]}] - (log/info "universal-links: handling community" community-id) - (navigation/navigate-to cofx :community {:community-id community-id})) - -(rf/defn handle-navigation-to-desktop-community-from-mobile - {:events [:handle-navigation-to-desktop-community-from-mobile]} - [cofx deserialized-key] - (rf/merge - cofx - {:dispatch [:navigate-to :community-overview deserialized-key]} - (navigation/pop-to-root :shell-stack))) - -(rf/defn handle-desktop-community - [_ {:keys [community-id]}] - (native-module/deserialize-and-compress-key - community-id - (fn [deserialized-key] - (rf/dispatch [:chat.ui/fetch-community (str deserialized-key)]) - (rf/dispatch [:handle-navigation-to-desktop-community-from-mobile (str deserialized-key)])))) - -(rf/defn handle-community-chat - [cofx {:keys [chat-id]}] - (log/info "universal-links: handling community chat" chat-id) - {:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]}) - (rf/defn handle-view-profile [{:keys [db] :as cofx} {:keys [public-key ens-name]}] (log/info "universal-links: handling view profile" public-key) @@ -143,14 +117,13 @@ (rf/defn on-handle {:events [::match-value]} - [cofx url {:keys [type] :as data}] + [cofx url {:keys [type chat-id] :as data}] (case type :group-chat (handle-group-chat cofx data) :private-chat (handle-private-chat cofx data) :community-requests (handle-community-requests cofx data) - :community (handle-community cofx data) - :desktop-community (handle-desktop-community cofx data) - :community-chat (handle-community-chat cofx data) + :community (communities.events/navigate-to-serialized-community cofx data) + :community-chat {:dispatch [:communities/navigate-to-community-chat chat-id :pop-to-root]} :contact (handle-view-profile cofx data) :browser (handle-browse cofx data) :eip681 (handle-eip681 cofx data) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 9155c6704aa..8bbe8968543 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -338,6 +338,13 @@ (def ^:const local-pairing-action-sync-device 3) (def ^:const local-pairing-action-pairing-installation 4) +(def ^:const serialization-key + "We pass this serialization key as a parameter to MultiformatSerializePublicKey + function at status-go, This key determines the output base of the serialization. + according to https://specs.status.im/spec/2#public-key-serialization we serialize + keys with base58btc encoding" + "z") + (def ^:const deserialization-key "We pass this deserialization key as a parameter to MultiformatDeserializePublicKey function at status-go, This key determines the output base of the deserialization. diff --git a/src/status_im/contexts/chat/home/add_new_contact/effects.cljs b/src/status_im/contexts/chat/home/add_new_contact/effects.cljs index 081059129df..4ff99915b4f 100644 --- a/src/status_im/contexts/chat/home/add_new_contact/effects.cljs +++ b/src/status_im/contexts/chat/home/add_new_contact/effects.cljs @@ -1,21 +1,7 @@ (ns status-im.contexts.chat.home.add-new-contact.effects (:require [legacy.status-im.ethereum.ens :as ens] - [native-module.core :as native-module] - [status-im.constants :as constants] - [utils.re-frame :as rf] - [utils.transforms :as transforms])) - -(rf/reg-fx :effects.contacts/decompress-public-key - (fn [{:keys [compressed-key on-success on-error]}] - (native-module/compressed-key->public-key - compressed-key - constants/deserialization-key - (fn [resp] - (let [{:keys [error]} (transforms/json->clj resp)] - (if error - (on-error error) - (on-success (str "0x" (subs resp 5))))))))) + [utils.re-frame :as rf])) (rf/reg-fx :effects.contacts/resolve-public-key-from-ens (fn [{:keys [chain-id ens on-success on-error]}] diff --git a/src/status_im/contexts/chat/home/add_new_contact/events.cljs b/src/status_im/contexts/chat/home/add_new_contact/events.cljs index f035661b502..e2be045fce1 100644 --- a/src/status_im/contexts/chat/home/add_new_contact/events.cljs +++ b/src/status_im/contexts/chat/home/add_new_contact/events.cljs @@ -104,7 +104,7 @@ :empty {:db (dissoc db :contacts/new-identity)} (:valid :invalid) {:db (assoc db :contacts/new-identity contact)} :decompress-key {:db (assoc db :contacts/new-identity contact) - :effects.contacts/decompress-public-key + :serialization/decompress-public-key {:compressed-key id :on-success (dispatcher :contacts/set-new-identity-success input) diff --git a/src/status_im/contexts/chat/home/add_new_contact/events_test.cljs b/src/status_im/contexts/chat/home/add_new_contact/events_test.cljs index 256e7ba1cc0..913fd00ef67 100644 --- a/src/status_im/contexts/chat/home/add_new_contact/events_test.cljs +++ b/src/status_im/contexts/chat/home/add_new_contact/events_test.cljs @@ -132,7 +132,7 @@ :type :compressed-key :public-key nil ; not yet... :state :decompress-key})) - :effects.contacts/decompress-public-key + :serialization/decompress-public-key {:compressed-key user-ckey :on-success [:contacts/set-new-identity-success user-ckey] :on-error [:contacts/set-new-identity-error user-ckey]}}))) diff --git a/src/status_im/contexts/chat/messenger/messages/link_preview/events.cljs b/src/status_im/contexts/chat/messenger/messages/link_preview/events.cljs index 70a640fe4ed..894c4f6e296 100644 --- a/src/status_im/contexts/chat/messenger/messages/link_preview/events.cljs +++ b/src/status_im/contexts/chat/messenger/messages/link_preview/events.cljs @@ -1,8 +1,6 @@ (ns status-im.contexts.chat.messenger.messages.link-preview.events (:require [camel-snake-kebab.core :as csk] - [legacy.status-im.mailserver.core :as mailserver] - [schema.core :as schema] [status-im.contexts.profile.settings.events :as profile.settings.events] [taoensso.timbre :as log] [utils.collection] @@ -42,96 +40,6 @@ (boolean enabled?) {})) -(defn community-resolved - [{:keys [db]} [community-id community]] - (when community - {:db (update db :communities/resolve-community-info dissoc community-id) - :fx [[:dispatch [:communities/handle-community community]] - [:dispatch - [:chat.ui/cache-link-preview-data (community-link community-id) community]]]})) - -(rf/reg-event-fx :chat.ui/community-resolved community-resolved) - -(defn community-failed-to-resolve - [{:keys [db]} [community-id]] - {:db (update db :communities/resolve-community-info dissoc community-id)}) - -(rf/reg-event-fx :chat.ui/community-failed-to-resolve community-failed-to-resolve) - -(defn fetch-community - [{:keys [db]} [community-id]] - (when community-id - {:db (assoc-in db [:communities/resolve-community-info community-id] true) - :json-rpc/call [{:method "wakuext_fetchCommunity" - :params [{:CommunityKey community-id - :TryDatabase true - :WaitForResponse true}] - :on-success (fn [community] - (rf/dispatch [:chat.ui/community-resolved community-id community])) - :on-error (fn [err] - (rf/dispatch [:chat.ui/community-failed-to-resolve community-id]) - (log/error {:message - "Failed to request community info from mailserver" - :error err}))}]})) - -(schema/=> fetch-community - [:=> - [:catn - [:cofx :schema.re-frame/cofx] - [:args - [:schema [:catn [:community-id [:? :string]]]]]] - [:maybe - [:map - [:db map?] - [:json-rpc/call :schema.common/rpc-call]]]]) - -(rf/reg-event-fx :chat.ui/fetch-community fetch-community) - -(defn spectate-community-success - [{:keys [db]} [{:keys [communities]}]] - (when-let [community (first communities)] - {:db (-> db - (assoc-in [:communities (:id community) :spectated] true) - (assoc-in [:communities (:id community) :spectating] false)) - :fx [[:dispatch [:communities/handle-community community]] - [:dispatch [::mailserver/request-messages]]]})) - -(rf/reg-event-fx :chat.ui/spectate-community-success spectate-community-success) - -(defn spectate-community-failed - [{:keys [db]} [community-id]] - {:db (assoc-in db [:communities community-id :spectating] false)}) - -(rf/reg-event-fx :chat.ui/spectate-community-failed spectate-community-failed) - -(defn spectate-community - [{:keys [db]} [community-id]] - (let [{:keys [spectated spectating joined]} (get-in db [:communities community-id])] - (when (and (not joined) (not spectated) (not spectating)) - {:db (assoc-in db [:communities community-id :spectating] true) - :json-rpc/call [{:method "wakuext_spectateCommunity" - :params [community-id] - :on-success [:chat.ui/spectate-community-success] - :on-error (fn [err] - (log/error {:message - "Failed to spectate community" - :error err}) - (rf/dispatch [:chat.ui/spectate-community-failed - community-id]))}]}))) - -(schema/=> spectate-community - [:=> - [:catn - [:cofx :schema.re-frame/cofx] - [:args - [:schema [:catn [:community-id [:? :string]]]]]] - [:maybe - [:map - [:db map?] - [:json-rpc/call :schema.common/rpc-call]]]]) - -(rf/reg-event-fx :chat.ui/spectate-community spectate-community) - (rf/defn save-link-preview-whitelist {:events [:chat.ui/link-preview-whitelist-received]} [{:keys [db]} whitelist] diff --git a/src/status_im/contexts/chat/messenger/messages/link_preview/events_test.cljs b/src/status_im/contexts/chat/messenger/messages/link_preview/events_test.cljs deleted file mode 100644 index 1c5fda33a97..00000000000 --- a/src/status_im/contexts/chat/messenger/messages/link_preview/events_test.cljs +++ /dev/null @@ -1,139 +0,0 @@ -(ns status-im.contexts.chat.messenger.messages.link-preview.events-test - (:require [cljs.test :as t] - [legacy.status-im.mailserver.core :as mailserver] - matcher-combinators.test - [status-im.contexts.chat.messenger.messages.link-preview.events :as sut])) - -(t/deftest fetch-community - (t/testing "with community id" - (t/testing "update resolving indicator in db" - (t/is (match? - {:db {:communities/resolve-community-info {"community-id" true}}} - (sut/fetch-community {} ["community-id"])))) - (t/testing "call the fetch community rpc method with correct community id" - (t/is (match? - {:json-rpc/call [{:method "wakuext_fetchCommunity" - :params [{:CommunityKey "community-id" - :TryDatabase true - :WaitForResponse true}]}]} - (sut/fetch-community {} ["community-id"]))))) - (t/testing "with no community id" - (t/testing "do nothing" - (t/is (match? - nil - (sut/fetch-community {} [])))))) - -(t/deftest community-failed-to-resolve - (t/testing "given a community id" - (t/testing "remove community id from resolving indicator in db" - (t/is (match? - nil - (get-in (sut/community-failed-to-resolve {:db {:communities/resolve-community-info - {"community-id" true}}} - ["community-id"]) - [:db :communities/resolve-community-info "community-id"])))))) - -(t/deftest community-resolved - (with-redefs [sut/community-link (fn [id] (str "community-link+" id))] - (t/testing "given a community" - (let [cofx {:db {:communities/resolve-community-info {"community-id" true}}} - arg ["community-id" {:id "community-id"}]] - (t/testing "remove community id from resolving indicator in db" - (t/is (match? - nil - (get-in (sut/community-resolved cofx arg) - [:db :communities/resolve-community-info "community-id"])))) - (t/testing "dispatch fxs" - (t/is (match? - {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] - [:dispatch - [:chat.ui/cache-link-preview-data "community-link+community-id" - {:id "community-id"}]]]} - (sut/community-resolved cofx arg)))))) - (t/testing "given a joined community" - (let [cofx {:db {:communities/resolve-community-info {"community-id" true}}} - arg ["community-id" {:id "community-id" :joined true}]] - (t/testing "dispatch fxs, do not spectate community" - (t/is (match? - {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] - [:dispatch - [:chat.ui/cache-link-preview-data "community-link+community-id" - {:id "community-id"}]]]} - (sut/community-resolved cofx arg)))))) - (t/testing "given a token-gated community" - (let [cofx {:db {:communities/resolve-community-info {"community-id" true}}} - arg ["community-id" {:id "community-id" :tokenPermissions [1]}]] - (t/testing "dispatch fxs, do not spectate community" - (t/is (match? - {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] - [:dispatch - [:chat.ui/cache-link-preview-data "community-link+community-id" - {:id "community-id"}]]]} - (sut/community-resolved cofx arg)))))) - (t/testing "given nil community" - (t/testing "do nothing" - (t/is (match? - nil - (sut/community-resolved {} ["community-id" nil]))))))) - -(t/deftest spectate-community - (t/testing "given a joined community" - (t/testing "do nothing" - (t/is (match? - nil - (sut/spectate-community {:db {:communities {"community-id" {:joined true}}}} - ["community-id"]))))) - (t/testing "given a spectated community" - (t/testing "do nothing" - (t/is (match? - nil - (sut/spectate-community {:db {:communities {"community-id" {:spectated true}}}} - ["community-id"]))))) - (t/testing "given a spectating community" - (t/testing "do nothing" - (t/is (match? - nil - (sut/spectate-community {:db {:communities {"community-id" {:spectating true}}}} - ["community-id"]))))) - (t/testing "given a community" - (t/testing "mark community spectating" - (t/is (match? - {:db {:communities {"community-id" {:spectating true}}}} - (sut/spectate-community {:db {:communities {"community-id" {}}}} ["community-id"])))) - (t/testing "call spectate community rpc with correct community id" - (t/is (match? - {:json-rpc/call [{:method "wakuext_spectateCommunity" - :params ["community-id"]}]} - (sut/spectate-community {:db {:communities {"community-id" {}}}} ["community-id"])))))) - -(t/deftest spectate-community-failed - (t/testing "mark community spectating false" - (t/is (match? - {:db {:communities {"community-id" {:spectating false}}}} - (sut/spectate-community-failed {} ["community-id"]))))) - -(t/deftest spectate-community-success - (t/testing "given communities" - (t/testing "mark first community spectating false" - (t/is (match? - {:db {:communities {"community-id" {:spectating false}}}} - (sut/spectate-community-success {} [{:communities [{:id "community-id"}]}])))) - (t/testing "mark first community spectated true" - (t/is (match? - {:db {:communities {"community-id" {:spectated true}}}} - (sut/spectate-community-success {} [{:communities [{:id "community-id"}]}])))) - (t/testing "dispatch fxs for first community" - (t/is (match? - {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] - [:dispatch [::mailserver/request-messages]]]} - (sut/spectate-community-success {} [{:communities [{:id "community-id"}]}]))))) - (t/testing "given empty community" - (t/testing "do nothing" - (t/is (match? - nil - (sut/spectate-community-success {} [{:communities []}]))))) - (t/testing "given nil community" - (t/testing "do nothing" - (t/is (match? - nil - (sut/spectate-community-success {} [])))))) diff --git a/src/status_im/contexts/chat/messenger/messages/link_preview/view.cljs b/src/status_im/contexts/chat/messenger/messages/link_preview/view.cljs index 5bf5fe9921f..788b994f923 100644 --- a/src/status_im/contexts/chat/messenger/messages/link_preview/view.cljs +++ b/src/status_im/contexts/chat/messenger/messages/link_preview/view.cljs @@ -81,7 +81,7 @@ (fn [] (when-not cached-preview-data (let [community-id (community-id-from-link community-link)] - (rf/dispatch [:chat.ui/fetch-community community-id])))) + (rf/dispatch [:communities/fetch-community community-id])))) :reagent-render (fn [] (when cached-preview-data diff --git a/src/status_im/contexts/communities/actions/token_gating/view.cljs b/src/status_im/contexts/communities/actions/token_gating/view.cljs index 8725aeb8753..5d237930dad 100644 --- a/src/status_im/contexts/communities/actions/token_gating/view.cljs +++ b/src/status_im/contexts/communities/actions/token_gating/view.cljs @@ -6,9 +6,8 @@ [utils.re-frame :as rf])) (defn token-requirements - [id] - (rf/dispatch [:communities/check-permissions-to-join-community id]) - (fn [] + [] + (fn [id] (let [{:keys [can-request-access? number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])] [rn/view {:style {:padding-horizontal 12}} diff --git a/src/status_im/contexts/communities/discover/view.cljs b/src/status_im/contexts/communities/discover/view.cljs index 7d632bf6562..7d596a629ba 100644 --- a/src/status_im/contexts/communities/discover/view.cljs +++ b/src/status_im/contexts/communities/discover/view.cljs @@ -20,11 +20,11 @@ [quo/community-card-view-item {:community (assoc item :cover cover) :width width - :on-press #(rf/dispatch [:navigate-to :community-overview (:id item)])}] + :on-press #(rf/dispatch [:communities/navigate-to-community-overview (:id item)])}] [quo/community-list-item {:on-press (fn [] (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:navigate-to :community-overview (:id item)])) + (rf/dispatch [:communities/navigate-to-community-overview (:id item)])) :on-long-press #(rf/dispatch [:show-bottom-sheet {:content (fn [] @@ -142,12 +142,13 @@ (if (= view-type :card-view) [quo/community-card-view-item {:community (assoc community :cover cover) - :on-press #(rf/dispatch [:navigate-to :community-overview (:id community)])}] + :on-press #(rf/dispatch [:communities/navigate-to-community-overview (:id community)])}] [quo/community-list-item {:on-press (fn [] (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:navigate-to :community-overview (:id community)])) + (rf/dispatch [:communities/navigate-to-community-overview + (:id community)])) :on-long-press #(js/alert "TODO: to be implemented")} community])])) (if communities communities communities-ids)) diff --git a/src/status_im/contexts/communities/events.cljs b/src/status_im/contexts/communities/events.cljs index e83de78643a..f38e373f069 100644 --- a/src/status_im/contexts/communities/events.cljs +++ b/src/status_im/contexts/communities/events.cljs @@ -1,12 +1,17 @@ (ns status-im.contexts.communities.events (:require [clojure.set :as set] + [clojure.string :as string] [clojure.walk :as walk] [legacy.status-im.data-store.chats :as data-store.chats] + [legacy.status-im.mailserver.core :as mailserver] [react-native.platform :as platform] [react-native.share :as share] + [schema.core :as schema] [status-im.constants :as constants] + [status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events] status-im.contexts.communities.actions.community-options.events status-im.contexts.communities.actions.leave.events + [status-im.navigation.events :as navigation] [taoensso.timbre :as log] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -71,14 +76,19 @@ (when community-js (let [{:keys [token-permissions token-permissions-check joined id] - :as community} (<-rpc community-js) - has-token-permissions? (not (seq token-permissions))] + :as community} (<-rpc community-js) + has-channel-perm? (fn [id-perm-tuple] + (let [{:keys [type]} (second id-perm-tuple)] + (or (= type constants/community-token-permission-can-view-channel) + (= + type + constants/community-token-permission-can-view-and-post-channel))))] {:db (assoc-in db [:communities id] community) - :fx [(when (and has-token-permissions? (not joined)) + :fx [(when (not joined) [:dispatch [:chat.ui/spectate-community id]]) - (when (and has-token-permissions? (nil? token-permissions-check)) + (when (nil? token-permissions-check) [:dispatch [:communities/check-permissions-to-join-community id]]) - (when (and has-token-permissions? (not (get-in db [:community-channels-permissions id]))) + (when (some has-channel-perm? token-permissions) [:dispatch [:communities/check-all-community-channels-permissions id]])]})))) (rf/defn handle-removed-chats @@ -267,3 +277,122 @@ (rf/reg-event-fx :communities/set-airdrop-address (fn [{:keys [db]} [address]] {:db (assoc db :communities/airdrop-address address)})) + +(defn community-fetched + [{:keys [db]} [community-id community]] + (when community + {:db (update db :communities/fetching-community dissoc community-id) + :fx [[:dispatch [:communities/handle-community community]] + [:dispatch + [:chat.ui/cache-link-preview-data (link-preview.events/community-link community-id) + community]]]})) + +(rf/reg-event-fx :chat.ui/community-fetched community-fetched) + +(defn community-failed-to-fetch + [{:keys [db]} [community-id]] + {:db (update db :communities/fetching-community dissoc community-id)}) + +(rf/reg-event-fx :chat.ui/community-failed-to-fetch community-failed-to-fetch) + +(defn fetch-community + [{:keys [db]} [community-id]] + (when (and community-id (not (get-in db [:communities/fetching-community community-id]))) + {:db (assoc-in db [:communities/fetching-community community-id] true) + :json-rpc/call [{:method "wakuext_fetchCommunity" + :params [{:CommunityKey community-id + :TryDatabase true + :WaitForResponse true}] + :on-success (fn [community] + (rf/dispatch [:chat.ui/community-fetched community-id community])) + :on-error (fn [err] + (rf/dispatch [:chat.ui/community-failed-to-fetch community-id]) + (log/error {:message + "Failed to request community info from mailserver" + :error err}))}]})) + +(schema/=> fetch-community + [:=> + [:catn + [:cofx :schema.re-frame/cofx] + [:args + [:schema [:catn [:community-id [:? :string]]]]]] + [:maybe + [:map + [:db map?] + [:json-rpc/call :schema.common/rpc-call]]]]) + +(rf/reg-event-fx :communities/fetch-community fetch-community) + +(defn spectate-community-success + [{:keys [db]} [{:keys [communities]}]] + (when-let [community (first communities)] + {:db (-> db + (assoc-in [:communities (:id community) :spectated] true) + (assoc-in [:communities (:id community) :spectating] false)) + :fx [[:dispatch [:communities/handle-community community]] + [:dispatch [::mailserver/request-messages]]]})) + +(rf/reg-event-fx :chat.ui/spectate-community-success spectate-community-success) + +(defn spectate-community-failed + [{:keys [db]} [community-id]] + {:db (assoc-in db [:communities community-id :spectating] false)}) + +(rf/reg-event-fx :chat.ui/spectate-community-failed spectate-community-failed) + +(defn spectate-community + [{:keys [db]} [community-id]] + (let [{:keys [spectated spectating joined]} (get-in db [:communities community-id])] + (when (and (not joined) (not spectated) (not spectating)) + {:db (assoc-in db [:communities community-id :spectating] true) + :json-rpc/call [{:method "wakuext_spectateCommunity" + :params [community-id] + :on-success [:chat.ui/spectate-community-success] + :on-error (fn [err] + (log/error {:message + "Failed to spectate community" + :error err}) + (rf/dispatch [:chat.ui/spectate-community-failed + community-id]))}]}))) + +(schema/=> spectate-community + [:=> + [:catn + [:cofx :schema.re-frame/cofx] + [:args + [:schema [:catn [:community-id [:? :string]]]]]] + [:maybe + [:map + [:db map?] + [:json-rpc/call :schema.common/rpc-call]]]]) + +(rf/reg-event-fx :chat.ui/spectate-community spectate-community) + +(rf/defn navigate-to-serialized-community + [_ {:keys [community-id]}] + {:serialization/deserialize-and-compress-key + {:serialized-key community-id + :on-success #(rf/dispatch [:communities/navigate-to-community-overview %]) + :on-error #(log/error {:message "Failed to decompress community-id" + :error % + :community-id community-id})}}) + +(rf/reg-event-fx :communities/navigate-to-community-overview + (fn [cofx [deserialized-key]] + (if (string/starts-with? deserialized-key constants/serialization-key) + (navigate-to-serialized-community cofx deserialized-key) + (rf/merge + cofx + {:fx [[:dispatch [:communities/fetch-community deserialized-key]] + [:dispatch [:navigate-to :community-overview deserialized-key]]]} + (navigation/pop-to-root :shell-stack))))) + +(rf/reg-event-fx :communities/navigate-to-community-chat + (fn [{:keys [db]} [chat-id pop-to-root?]] + (let [{:keys [community-id]} (get-in db [:chats chat-id])] + {:fx [(when community-id + [:dispatch [:communities/fetch-community community-id]]) + (if pop-to-root? + [:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]] + [:dispatch [:chat/navigate-to-chat chat-id]])]}))) diff --git a/src/status_im/contexts/communities/events_test.cljs b/src/status_im/contexts/communities/events_test.cljs index fc36e6698ee..c7958cca134 100644 --- a/src/status_im/contexts/communities/events_test.cljs +++ b/src/status_im/contexts/communities/events_test.cljs @@ -1,6 +1,8 @@ (ns status-im.contexts.communities.events-test - (:require [cljs.test :refer [deftest is]] + (:require [cljs.test :refer [deftest is testing]] + [legacy.status-im.mailserver.core :as mailserver] matcher-combinators.test + [status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events] [status-im.contexts.communities.events :as events])) (deftest initialize-permission-addresses-test @@ -50,3 +52,137 @@ (is (match? expected-db (events/update-previous-permission-addresses initial-db)))))) + +(deftest fetch-community + (testing "with community id" + (testing "update fetching indicator in db" + (is (match? + {:db {:communities/fetching-community {"community-id" true}}} + (events/fetch-community {} ["community-id"])))) + (testing "call the fetch community rpc method with correct community id" + (is (match? + {:json-rpc/call [{:method "wakuext_fetchCommunity" + :params [{:CommunityKey "community-id" + :TryDatabase true + :WaitForResponse true}]}]} + (events/fetch-community {} ["community-id"]))))) + (testing "with no community id" + (testing "do nothing" + (is (match? + nil + (events/fetch-community {} [])))))) + +(deftest community-failed-to-fetch + (testing "given a community id" + (testing "remove community id from fetching indicator in db" + (is (match? + nil + (get-in (events/community-failed-to-fetch {:db {:communities/fetching-community + {"community-id" true}}} + ["community-id"]) + [:db :communities/fetching-community "community-id"])))))) + +(deftest community-fetched + (with-redefs [link-preview.events/community-link (fn [id] (str "community-link+" id))] + (testing "given a community" + (let [cofx {:db {:communities/fetching-community {"community-id" true}}} + arg ["community-id" {:id "community-id"}]] + (testing "remove community id from fetching indicator in db" + (is (match? + nil + (get-in (events/community-fetched cofx arg) + [:db :communities/fetching-community "community-id"])))) + (testing "dispatch fxs" + (is (match? + {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] + [:dispatch + [:chat.ui/cache-link-preview-data "community-link+community-id" + {:id "community-id"}]]]} + (events/community-fetched cofx arg)))))) + (testing "given a joined community" + (let [cofx {:db {:communities/fetching-community {"community-id" true}}} + arg ["community-id" {:id "community-id" :joined true}]] + (testing "dispatch fxs, do not spectate community" + (is (match? + {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] + [:dispatch + [:chat.ui/cache-link-preview-data "community-link+community-id" + {:id "community-id"}]]]} + (events/community-fetched cofx arg)))))) + (testing "given a token-gated community" + (let [cofx {:db {:communities/fetching-community {"community-id" true}}} + arg ["community-id" {:id "community-id" :tokenPermissions [1]}]] + (testing "dispatch fxs, do not spectate community" + (is (match? + {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] + [:dispatch + [:chat.ui/cache-link-preview-data "community-link+community-id" + {:id "community-id"}]]]} + (events/community-fetched cofx arg)))))) + (testing "given nil community" + (testing "do nothing" + (is (match? + nil + (events/community-fetched {} ["community-id" nil]))))))) + +(deftest spectate-community + (testing "given a joined community" + (testing "do nothing" + (is (match? + nil + (events/spectate-community {:db {:communities {"community-id" {:joined true}}}} + ["community-id"]))))) + (testing "given a spectated community" + (testing "do nothing" + (is (match? + nil + (events/spectate-community {:db {:communities {"community-id" {:spectated true}}}} + ["community-id"]))))) + (testing "given a spectating community" + (testing "do nothing" + (is (match? + nil + (events/spectate-community {:db {:communities {"community-id" {:spectating true}}}} + ["community-id"]))))) + (testing "given a community" + (testing "mark community spectating" + (is (match? + {:db {:communities {"community-id" {:spectating true}}}} + (events/spectate-community {:db {:communities {"community-id" {}}}} ["community-id"])))) + (testing "call spectate community rpc with correct community id" + (is (match? + {:json-rpc/call [{:method "wakuext_spectateCommunity" + :params ["community-id"]}]} + (events/spectate-community {:db {:communities {"community-id" {}}}} ["community-id"])))))) + +(deftest spectate-community-failed + (testing "mark community spectating false" + (is (match? + {:db {:communities {"community-id" {:spectating false}}}} + (events/spectate-community-failed {} ["community-id"]))))) + +(deftest spectate-community-success + (testing "given communities" + (testing "mark first community spectating false" + (is (match? + {:db {:communities {"community-id" {:spectating false}}}} + (events/spectate-community-success {} [{:communities [{:id "community-id"}]}])))) + (testing "mark first community spectated true" + (is (match? + {:db {:communities {"community-id" {:spectated true}}}} + (events/spectate-community-success {} [{:communities [{:id "community-id"}]}])))) + (testing "dispatch fxs for first community" + (is (match? + {:fx [[:dispatch [:communities/handle-community {:id "community-id"}]] + [:dispatch [::mailserver/request-messages]]]} + (events/spectate-community-success {} [{:communities [{:id "community-id"}]}]))))) + (testing "given empty community" + (testing "do nothing" + (is (match? + nil + (events/spectate-community-success {} [{:communities []}]))))) + (testing "given nil community" + (testing "do nothing" + (is (match? + nil + (events/spectate-community-success {} [])))))) diff --git a/src/status_im/contexts/communities/home/view.cljs b/src/status_im/contexts/communities/home/view.cljs index 76dd8986655..021eb3cbf0f 100644 --- a/src/status_im/contexts/communities/home/view.cljs +++ b/src/status_im/contexts/communities/home/view.cljs @@ -26,7 +26,8 @@ [quo/communities-membership-list-item {:customization-color customization-color :style {:padding-horizontal 20} - :on-press #(debounce/dispatch-and-chill [:navigate-to :community-overview id] 500) + :on-press #(debounce/dispatch-and-chill [:communities/navigate-to-community-overview id] + 500) :on-long-press #(rf/dispatch [:show-bottom-sheet {:content (fn [] diff --git a/src/status_im/contexts/communities/overview/view.cljs b/src/status_im/contexts/communities/overview/view.cljs index a90755146aa..51c8e47887f 100644 --- a/src/status_im/contexts/communities/overview/view.cljs +++ b/src/status_im/contexts/communities/overview/view.cljs @@ -137,8 +137,7 @@ [quo/icon :i/info {:no-color true}]]]) (defn token-gates - [{:keys [id]}] - (rf/dispatch [:communities/check-permissions-to-join-community id]) + [] (fn [{:keys [id color]}] (let [{:keys [can-request-access? number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])] @@ -222,8 +221,9 @@ {:on-press (when joined-or-spectated (fn [] (rf/dispatch [:dismiss-keyboard]) - (debounce/dispatch-and-chill [:chat/navigate-to-chat (str community-id id)] - 1000))) + (debounce/dispatch-and-chill + [:communities/navigate-to-community-chat (str community-id id)] + 1000))) :on-long-press #(rf/dispatch [:show-bottom-sheet {:content (fn [] diff --git a/src/status_im/contexts/shell/activity_center/notification/community_request/view.cljs b/src/status_im/contexts/shell/activity_center/notification/community_request/view.cljs index 147c62a69eb..dc2cbe9230b 100644 --- a/src/status_im/contexts/shell/activity_center/notification/community_request/view.cljs +++ b/src/status_im/contexts/shell/activity_center/notification/community_request/view.cljs @@ -71,7 +71,7 @@ [gesture/touchable-without-feedback {:on-press (fn [] (rf/dispatch [:navigate-back]) - (rf/dispatch [:navigate-to :community-overview community-id]))} + (rf/dispatch [:communities/navigate-to-community-overview community-id]))} [quo/activity-log {:title header-text :customization-color customization-color diff --git a/src/status_im/contexts/shell/jump_to/components/switcher_cards/view.cljs b/src/status_im/contexts/shell/jump_to/components/switcher_cards/view.cljs index 9dbb89a32bf..654d58a7152 100644 --- a/src/status_im/contexts/shell/jump_to/components/switcher_cards/view.cljs +++ b/src/status_im/contexts/shell/jump_to/components/switcher_cards/view.cljs @@ -197,10 +197,10 @@ (rf/dispatch [:chat/navigate-to-chat id]) (= card-type shell.constants/community-channel-card) - (rf/dispatch [:chat/navigate-to-chat channel-id]) + (rf/dispatch [:communities/navigate-to-community-chat channel-id]) (= card-type shell.constants/community-card) - (rf/dispatch [:navigate-to :community-overview id]))) + (rf/dispatch [:communities/navigate-to-community-overview id]))) (defn calculate-card-position-and-open-screen [card-ref card-type id channel-id] diff --git a/src/status_im/subs/communities.cljs b/src/status_im/subs/communities.cljs index 6871b08a368..9c3856a4c6f 100644 --- a/src/status_im/subs/communities.cljs +++ b/src/status_im/subs/communities.cljs @@ -8,7 +8,7 @@ (re-frame/reg-sub :communities/fetching-community - :<- [:communities/resolve-community-info] + :<- [:communities/fetching-community] (fn [info [_ id]] (get info id))) diff --git a/src/status_im/subs/root.cljs b/src/status_im/subs/root.cljs index 6be147a51db..58d81137950 100644 --- a/src/status_im/subs/root.cljs +++ b/src/status_im/subs/root.cljs @@ -140,7 +140,7 @@ (reg-root-key-sub :communities/channels-permissions :community-channels-permissions) (reg-root-key-sub :communities/requests-to-join :communities/requests-to-join) (reg-root-key-sub :communities/community-id-input :communities/community-id-input) -(reg-root-key-sub :communities/resolve-community-info :communities/resolve-community-info) +(reg-root-key-sub :communities/fetching-community :communities/fetching-community) (reg-root-key-sub :communities/my-pending-requests-to-join :communities/my-pending-requests-to-join) (reg-root-key-sub :communities/collapsed-categories :communities/collapsed-categories) (reg-root-key-sub :communities/selected-tab :communities/selected-tab)