From e5dbac877e0bc18ea20e5f31c441c46cec34c64c Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Thu, 26 Mar 2020 12:36:41 +0100 Subject: [PATCH] Handle new universal links Fixes: #10192 Fixes: #10083 Signed-off-by: Andrea Maria Piana --- src/status_im/events.cljs | 8 ++++- src/status_im/multiaccounts/login/core.cljs | 2 -- src/status_im/transport/filters/core.cljs | 10 ++++-- src/status_im/utils/universal_links/core.cljs | 23 ++++++++------ .../dapps_and_browsing/test_deep_links.py | 26 ++++++---------- test/appium/views/base_element.py | 2 +- test/appium/views/base_view.py | 14 ++++++--- test/appium/views/sign_in_view.py | 1 + .../test/utils/universal_links/core.cljs | 31 +++++++++++++++++-- 9 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index acd234bc62..cc23e238c5 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -31,6 +31,7 @@ [status-im.init.core :as init] [status-im.log-level.core :as log-level] status-im.waku.core + [status-im.utils.universal-links.core :as universal-links] [status-im.mailserver.core :as mailserver] [status-im.mailserver.constants :as mailserver.constants] [status-im.mailserver.topics :as mailserver.topics] @@ -145,6 +146,11 @@ (update :hardwallet dissoc :application-info))} (multiaccounts.login/open-login key-uid photo-path name public-key))))) +(handlers/register-handler-fx + :login/filters-initialized + (fn [cofx] + (universal-links/process-stored-event cofx))) + ;; multiaccounts update module (handlers/register-handler-fx @@ -1180,4 +1186,4 @@ (fn [{:keys [db]} [_ theme]] (let [cur-theme (get-in db [:multiaccount :appearance])] (when (or (nil? cur-theme) (zero? cur-theme)) - {::multiaccounts/switch-theme (if (= :dark theme) 2 1)})))) \ No newline at end of file + {::multiaccounts/switch-theme (if (= :dark theme) 2 1)})))) diff --git a/src/status_im/multiaccounts/login/core.cljs b/src/status_im/multiaccounts/login/core.cljs index b99cef99e2..70a5a4cbe1 100644 --- a/src/status_im/multiaccounts/login/core.cljs +++ b/src/status_im/multiaccounts/login/core.cljs @@ -24,7 +24,6 @@ [status-im.utils.platform :as platform] [status-im.utils.security :as security] [status-im.utils.types :as types] - [status-im.utils.universal-links.core :as universal-links] [status-im.utils.utils :as utils] [status-im.wallet.core :as wallet] [taoensso.timbre :as log] @@ -208,7 +207,6 @@ ;; NOTE: initializing mailserver depends on user mailserver ;; preference which is why we wait for config callback (protocol/initialize-protocol {:default-mailserver true}) - (universal-links/process-stored-event) (check-network-version network-id) (chat.loading/initialize-chats) (contact/initialize-contacts) diff --git a/src/status_im/transport/filters/core.cljs b/src/status_im/transport/filters/core.cljs index 86e0fcd8dc..ee82f44c2e 100644 --- a/src/status_im/transport/filters/core.cljs +++ b/src/status_im/transport/filters/core.cljs @@ -206,13 +206,17 @@ :discovery? discovery :topic topic}) -(fx/defn set-filters-initialized [{:keys [db]}] - {:db (update db :filters/initialized inc)}) - ;; We check that both chats & contacts have been initialized (defn filters-initialized? [db] (>= (:filters/initialized db) 2)) +(fx/defn set-filters-initialized [{:keys [db] :as cofx}] + (fx/merge + cofx + {:db (update db :filters/initialized inc)} + #(when (filters-initialized? (:db %)) + {:dispatch [:login/filters-initialized]}))) + (fx/defn handle-filters-added "Called every time we load a filter from statusgo, either from explicit call or through signals. It stores the filter in the db and upsert the relevant diff --git a/src/status_im/utils/universal_links/core.cljs b/src/status_im/utils/universal_links/core.cljs index 051292a408..0f9b8046eb 100644 --- a/src/status_im/utils/universal_links/core.cljs +++ b/src/status_im/utils/universal_links/core.cljs @@ -21,17 +21,17 @@ ;; TODO(yenda) investigate why `handle-universal-link` event is ;; dispatched 7 times for the same link -(def public-chat-regex #".*/chat/public/(.*)$") -(def profile-regex #".*/user/(.*)$") -(def browse-regex #".*/browse/(.*)$") +(def public-chat-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:chat/public/([a-z0-9\-]+)$|([a-z0-9\-]+))$") +(def profile-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:u/(0x.*)$|u/(.*)$|user/(.*))$") +(def browse-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:b/(.*)$|browse/(.*))$") ;; domains should be without the trailing slash (def domains {:external "https://join.status.im" :internal "status-im:/"}) -(def links {:public-chat "%s/chat/public/%s" - :user "%s/user/%s" - :browse "%s/browse/%s"}) +(def links {:public-chat "%s/%s" + :user "%s/u/%s" + :browse "%s/b/%s"}) (defn generate-link [link-type domain-type param] (gstring/format (get links link-type) @@ -41,7 +41,10 @@ (defn match-url [url regex] (some->> url (re-matches regex) - peek)) + rest + reverse + (remove nil?) + first)) (defn is-request-url? [url] (string/starts-with? url "ethereum:")) @@ -116,8 +119,6 @@ "Match a url against a list of routes and handle accordingly" [cofx url] (cond - (match-url url public-chat-regex) - (handle-public-chat cofx (match-url url public-chat-regex)) (spec/valid? :global/public-key (match-url url profile-regex)) (handle-view-profile cofx {:public-key (match-url url profile-regex)}) @@ -132,6 +133,10 @@ (is-request-url? url) (handle-eip681 cofx url) + ;; This needs to stay last, as it's a bit of a catch-all regex + (match-url url public-chat-regex) + (handle-public-chat cofx (match-url url public-chat-regex)) + :else (handle-not-found url))) (fx/defn store-url-for-later diff --git a/test/appium/tests/atomic/dapps_and_browsing/test_deep_links.py b/test/appium/tests/atomic/dapps_and_browsing/test_deep_links.py index 17e50ad6ba..106a47e221 100644 --- a/test/appium/tests/atomic/dapps_and_browsing/test_deep_links.py +++ b/test/appium/tests/atomic/dapps_and_browsing/test_deep_links.py @@ -10,14 +10,12 @@ class TestDeepLinks(SingleDeviceTestCase): @marks.testrail_id(5396) @marks.high - @marks.skip - # TODO: skipped because universal links won't work in emulators regardless of OS version def test_open_public_chat_using_deep_link(self): sign_in_view = SignInView(self.driver) sign_in_view.create_user() self.driver.close_app() chat_name = sign_in_view.get_public_chat_name() - deep_link = 'https://join.status.im/chat/public/%s' % chat_name + deep_link = 'https://join.status.im/%s' % chat_name sign_in_view.open_weblink_and_login(deep_link) chat_view = sign_in_view.get_chat_view() try: @@ -27,30 +25,28 @@ class TestDeepLinks(SingleDeviceTestCase): @marks.testrail_id(5441) @marks.medium - @marks.skip - # TODO: skipped because universal links won't work in emulators regardless of OS version def test_open_user_profile_using_deep_link(self): sign_in_view = SignInView(self.driver) sign_in_view.create_user() - for user_ident in ens_user['ens'], basic_user['public_key']: + profile = sign_in_view.profile_button.click() + profile.switch_network('Mainnet with upstream RPC') + for user_ident in ens_user['ens'], ens_user['ens_another_domain'], ens_user['public_key'],: self.driver.close_app() - deep_link = 'https://join.status.im/user/%s' % user_ident + deep_link = 'https://join.status.im/u/%s' % user_ident sign_in_view.open_weblink_and_login(deep_link) chat_view = sign_in_view.get_chat_view() - for text in basic_user['username'], 'Add to contacts': + for text in ens_user['username'], 'Add to contacts': if not chat_view.element_by_text(text).scroll_to_element(10): self.driver.fail("User profile screen is not opened") @marks.testrail_id(5442) @marks.medium - @marks.skip - # TODO: skipped because universal links won't work in emulators regardless of OS version def test_open_dapp_using_deep_link(self): sign_in_view = SignInView(self.driver) sign_in_view.create_user() self.driver.close_app() dapp_name = test_dapp_url - dapp_deep_link = 'https://join.status.im/browse/%s' % dapp_name + dapp_deep_link = 'https://join.status.im/b/%s' % dapp_name sign_in_view.open_weblink_and_login(dapp_deep_link) web_view = sign_in_view.get_chat_view() try: @@ -61,13 +57,11 @@ class TestDeepLinks(SingleDeviceTestCase): @marks.testrail_id(5780) @marks.medium - @marks.skip - # TODO: skipped because universal links won't work in emulators regardless of OS version def test_open_own_user_profile_using_deep_link(self): sign_in_view = SignInView(self.driver) sign_in_view.recover_access(passphrase=basic_user['passphrase']) self.driver.close_app() - deep_link = 'https://join.status.im/user/%s' % basic_user['public_key'] + deep_link = 'https://join.status.im/u/%s' % basic_user['public_key'] sign_in_view.open_weblink_and_login(deep_link) profile_view = sign_in_view.get_profile_view() if profile_view.default_username_text.text != basic_user['username'] \ @@ -77,13 +71,11 @@ class TestDeepLinks(SingleDeviceTestCase): @marks.testrail_id(5781) @marks.medium - @marks.skip - # TODO: skipped because universal links won't work in emulators regardless of OS version def test_deep_link_with_invalid_user_public_key(self): sign_in_view = SignInView(self.driver) sign_in_view.create_user() self.driver.close_app() - deep_link = 'https://join.status.im/user/%s' % basic_user['public_key'][:-10] + deep_link = 'https://join.status.im/u/%s' % basic_user['public_key'][:-10] sign_in_view.open_weblink_and_login(deep_link) home_view = sign_in_view.get_home_view() home_view.plus_button.click_until_presence_of_element(home_view.start_new_chat_button) diff --git a/test/appium/views/base_element.py b/test/appium/views/base_element.py index 07e02709e6..930e9b4e7d 100644 --- a/test/appium/views/base_element.py +++ b/test/appium/views/base_element.py @@ -184,7 +184,7 @@ class BaseElement(object): width, height = size['width'], size['height'] self.driver.swipe(start_x=x + width * 0.75, start_y=y + height / 2, end_x=x, end_y=y + height / 2) - def swipe_to_web_element(self, depth=400): + def swipe_to_web_element(self, depth=700): element = self.find_element() location = element.location x, y = location['x'], location['y'] diff --git a/test/appium/views/base_view.py b/test/appium/views/base_view.py index 01e47107a2..aa8b70f4d3 100644 --- a/test/appium/views/base_view.py +++ b/test/appium/views/base_view.py @@ -43,11 +43,13 @@ class AllowButton(BaseButton): except NoSuchElementException: pass + class SearchEditBox(BaseEditBox): def __init__(self, driver): super(SearchEditBox, self).__init__(driver) self.locator = self.Locator.text_selector("Search or type web address") + class DenyButton(BaseButton): def __init__(self, driver): super(DenyButton, self).__init__(driver) @@ -402,6 +404,13 @@ class BaseView(object): pass iterations += 1 + def rooted_device_continue(self): + try: + self.continue_button.wait_for_element(3) + self.continue_button.click() + except (NoSuchElementException, TimeoutException): + pass + def close_native_device_dialog(self, alert_text_part): element = self.element_by_text_part(alert_text_part) if element.is_element_present(1): @@ -673,12 +682,9 @@ class BaseView(object): self.driver.back() self.driver.back() - def open_universal_web_link(self, deep_link): start_web_browser(self.driver) - self.search_in_google_edit_box.set_value(deep_link) - self.confirm() - self.open_in_status_button.click() + self.driver.get(deep_link) # Method-helper def write_page_source_to_file(self, full_path_to_file): diff --git a/test/appium/views/sign_in_view.py b/test/appium/views/sign_in_view.py index 81e9b118bb..251640929e 100644 --- a/test/appium/views/sign_in_view.py +++ b/test/appium/views/sign_in_view.py @@ -248,4 +248,5 @@ class SignInView(BaseView): def open_weblink_and_login(self, url_weblink): self.open_universal_web_link(url_weblink) + self.rooted_device_continue() self.sign_in() diff --git a/test/cljs/status_im/test/utils/universal_links/core.cljs b/test/cljs/status_im/test/utils/universal_links/core.cljs index 38a966d3e1..151b6bc1dc 100644 --- a/test/cljs/status_im/test/utils/universal_links/core.cljs +++ b/test/cljs/status_im/test/utils/universal_links/core.cljs @@ -19,26 +19,53 @@ (is (nil? (get-in (links/handle-url {:db db} "some-url") [:db :universal-links/url])))) (testing "a public chat link" + (testing "it joins the chat, short version" + (is (get-in (links/handle-url {:db db} "status-im://status") + [:db :chats "status"]))) + (testing "it joins the chat, short version, https" + (is (get-in (links/handle-url {:db db} "https://join.status.im/status") + [:db :chats "status"]))) (testing "it joins the chat" (is (get-in (links/handle-url {:db db} "status-im://chat/public/status") [:db :chats "status"])))) - (testing "a browse dapp link" + (testing "it open the dapps short version" + (is + (= "www.cryptokitties.co" + (:browser/show-browser-selection (links/handle-url {:db db} "status-im://b/www.cryptokitties.co"))))) + (testing "it open the dapps short version, https" + (is + (= "www.cryptokitties.co" + (:browser/show-browser-selection (links/handle-url {:db db} "https://join.status.im/b/www.cryptokitties.co"))))) (testing "it open the dapps" (is (= "www.cryptokitties.co" (:browser/show-browser-selection (links/handle-url {:db db} "status-im://browse/www.cryptokitties.co")))))) (testing "a user profile link" + (testing "it loads the profile, short version" + (let [actual (links/handle-url {:db db} "status-im://u/0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")] + (is (= "0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073" (get-in actual [:db :contacts/identity]))))) + (testing "it loads the profile, short version https" + (let [actual (links/handle-url {:db db} "https://join.status.im/u/0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")] + (is (= "0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073" (get-in actual [:db :contacts/identity]))))) (testing "it loads the profile" (let [actual (links/handle-url {:db db} "status-im://user/0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")] (is (= "0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073" (get-in actual [:db :contacts/identity])))))) + (testing "Handle a custom string as a an profile link with ens-name" + (is (= (get-in (links/handle-url {:db db} "status-im://u/CONTACTCODE") + [:resolve-public-key :contact-identity]) + "CONTACTCODE"))) + (testing "Handle a custom string as a an profile link with ens-name, http" + (is (= (get-in (links/handle-url {:db db} "https://join.status.im/u/statuse2e") + [:resolve-public-key :contact-identity]) + "statuse2e"))) (testing "Handle a custom string as a an profile link with ens-name" (is (= (get-in (links/handle-url {:db db} "status-im://user/CONTACTCODE") [:resolve-public-key :contact-identity]) "CONTACTCODE"))) (testing "a not found url" (testing "it does nothing" - (is (nil? (links/handle-url {:db db} "status-im://not-existing"))))))))) + (is (nil? (links/handle-url {:db db} "status-im://blah/not-existing"))))))))) (deftest url-event-listener (testing "the url is not nil"