[mentions] Replace all mentions with public keys before sending message
This commit is contained in:
parent
001789f761
commit
2934de9b8c
|
@ -9,7 +9,8 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
["emojilib" :as emojis]))
|
["emojilib" :as emojis]
|
||||||
|
[status-im.chat.models.mentions :as mentions]))
|
||||||
|
|
||||||
(defn text->emoji
|
(defn text->emoji
|
||||||
"Replaces emojis in a specified `text`"
|
"Replaces emojis in a specified `text`"
|
||||||
|
@ -130,7 +131,8 @@
|
||||||
(fx/defn send-current-message
|
(fx/defn send-current-message
|
||||||
"Sends message from current chat input"
|
"Sends message from current chat input"
|
||||||
[{{:keys [current-chat-id] :as db} :db :as cofx}]
|
[{{:keys [current-chat-id] :as db} :db :as cofx}]
|
||||||
(let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])]
|
(let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])
|
||||||
|
input-text-with-mentions (mentions/check-mentions cofx input-text)]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(send-image)
|
(send-image)
|
||||||
(send-plain-text-message input-text current-chat-id))))
|
(send-plain-text-message input-text-with-mentions current-chat-id))))
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
(ns status-im.chat.models.mentions
|
||||||
|
(:require [clojure.string :as string]
|
||||||
|
[status-im.contact.db :as contact.db]))
|
||||||
|
|
||||||
|
(defn get-mentionable-users
|
||||||
|
[{{:keys [current-chat-id messages]
|
||||||
|
:contacts/keys [contacts] :as db} :db}]
|
||||||
|
(let [{:keys [group-chat public?] :as chat}
|
||||||
|
(get-in db [:chats current-chat-id])
|
||||||
|
chat-specific-suggestions
|
||||||
|
(cond
|
||||||
|
(and group-chat (not public?))
|
||||||
|
(let [{:keys [public-key]} (:multiaccount db)
|
||||||
|
all-contacts (:contacts/contacts db)
|
||||||
|
group-contacts
|
||||||
|
(contact.db/get-all-contacts-in-group-chat
|
||||||
|
(disj (:contacts chat) public-key)
|
||||||
|
nil
|
||||||
|
all-contacts
|
||||||
|
nil)]
|
||||||
|
(reduce
|
||||||
|
(fn [acc {:keys [alias public-key identicon name]}]
|
||||||
|
(assoc acc alias
|
||||||
|
{:alias alias
|
||||||
|
:identicon identicon
|
||||||
|
:public-key public-key
|
||||||
|
:name name}))
|
||||||
|
{}
|
||||||
|
group-contacts))
|
||||||
|
|
||||||
|
(and group-chat public?)
|
||||||
|
(reduce
|
||||||
|
(fn [acc [_ {:keys [alias name identicon from]}]]
|
||||||
|
(assoc acc alias {:alias alias
|
||||||
|
:name (or name alias)
|
||||||
|
:identicon identicon
|
||||||
|
:public-key from}))
|
||||||
|
nil
|
||||||
|
(get messages current-chat-id))
|
||||||
|
|
||||||
|
:else {})]
|
||||||
|
(reduce
|
||||||
|
(fn [acc [key {:keys [alias name identicon]}]]
|
||||||
|
(let [name (string/replace name ".stateofus.eth" "")]
|
||||||
|
(assoc acc alias {:alias alias
|
||||||
|
:name (or name alias)
|
||||||
|
:identicon identicon
|
||||||
|
:public-key key})))
|
||||||
|
chat-specific-suggestions
|
||||||
|
contacts)))
|
||||||
|
|
||||||
|
(def word-regex #"^[\S]*\s|^[\S]*$")
|
||||||
|
|
||||||
|
(defn mentioned? [{:keys [alias name]} text]
|
||||||
|
(let [lcase-name (string/lower-case name)
|
||||||
|
lcase-alias (string/lower-case alias)
|
||||||
|
regex (re-pattern
|
||||||
|
(string/join
|
||||||
|
"|"
|
||||||
|
[(str "^" lcase-name "\\s")
|
||||||
|
(str "^" lcase-name "$")
|
||||||
|
(str "^" lcase-alias "\\s")
|
||||||
|
(str "^" lcase-alias "$")]))
|
||||||
|
lcase-text (string/lower-case text)]
|
||||||
|
(re-find regex lcase-text)))
|
||||||
|
|
||||||
|
(defn match-mention
|
||||||
|
([text users mention-key-idx]
|
||||||
|
(match-mention text users mention-key-idx (inc mention-key-idx) []))
|
||||||
|
([text users mention-key-idx next-word-idx words]
|
||||||
|
(let [trimmed-text (subs text next-word-idx)]
|
||||||
|
(when-let [word (string/trim (re-find word-regex trimmed-text))]
|
||||||
|
(let [words (conj words word)
|
||||||
|
searched-text (string/lower-case (string/join " " words))
|
||||||
|
suggestions (filter
|
||||||
|
(fn [[_ {:keys [alias name]}]]
|
||||||
|
(let [names (set [alias name])]
|
||||||
|
(some
|
||||||
|
(fn [username]
|
||||||
|
(string/starts-with?
|
||||||
|
(string/lower-case username)
|
||||||
|
searched-text))
|
||||||
|
names)))
|
||||||
|
users)
|
||||||
|
suggestions-cnt (count suggestions)]
|
||||||
|
(cond (zero? suggestions-cnt)
|
||||||
|
nil
|
||||||
|
|
||||||
|
(and (= 1 suggestions-cnt)
|
||||||
|
(mentioned? (second (first suggestions))
|
||||||
|
(subs text (inc mention-key-idx))))
|
||||||
|
(second (first suggestions))
|
||||||
|
|
||||||
|
(> suggestions-cnt 1)
|
||||||
|
(let [word-len (count word)
|
||||||
|
text-len (count text)
|
||||||
|
next-word-start (+ next-word-idx (inc word-len))]
|
||||||
|
(when (> text-len next-word-start)
|
||||||
|
(match-mention text users mention-key-idx
|
||||||
|
next-word-start words)))))))))
|
||||||
|
|
||||||
|
(defn replace-mentions
|
||||||
|
([text users-fn]
|
||||||
|
(replace-mentions text users-fn 0))
|
||||||
|
([text users-fn idx]
|
||||||
|
(let [mention-key-idx (string/index-of text "@" idx)]
|
||||||
|
(if-not mention-key-idx
|
||||||
|
text
|
||||||
|
(let [users (users-fn)
|
||||||
|
{:keys [public-key alias]}
|
||||||
|
(match-mention text users mention-key-idx)]
|
||||||
|
(if-not alias
|
||||||
|
(recur text (fn [] users) (inc mention-key-idx))
|
||||||
|
(let [new-text (string/join
|
||||||
|
[(subs text 0 (inc mention-key-idx))
|
||||||
|
public-key
|
||||||
|
(subs text (+ (inc mention-key-idx)
|
||||||
|
(count alias)))])
|
||||||
|
mention-end (+ (inc mention-key-idx) (count public-key))]
|
||||||
|
(recur new-text (fn [] users) mention-end))))))))
|
||||||
|
|
||||||
|
(defn check-mentions [cofx text]
|
||||||
|
(replace-mentions text #(get-mentionable-users cofx)))
|
|
@ -0,0 +1,78 @@
|
||||||
|
(ns status-im.chat.models.mentions-test
|
||||||
|
(:require [status-im.chat.models.mentions :as mentions]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[cljs.test :as test :include-macros true]))
|
||||||
|
|
||||||
|
(test/deftest test-replace-mentions
|
||||||
|
(let [users (fn []
|
||||||
|
{"User Number One"
|
||||||
|
{:name "User Number One"
|
||||||
|
:alias "User Number One"
|
||||||
|
:public-key "0xpk1"}
|
||||||
|
"User Number Two"
|
||||||
|
{:name "user2"
|
||||||
|
:alias "User Number Two"
|
||||||
|
:public-key "0xpk2"}
|
||||||
|
"User Number Three"
|
||||||
|
{:name "user3"
|
||||||
|
:alias "User Number Three"
|
||||||
|
:public-key "0xpk3"}})]
|
||||||
|
(test/testing "no mentions"
|
||||||
|
(let [text "foo bar @buzz kek @foo"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result text) (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "starts with mention"
|
||||||
|
(let [text "@User Number One"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "@0xpk1") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "starts with mention but no space after"
|
||||||
|
(let [text "@User Number Onefoo"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result text) (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "starts with mention, some text after mention"
|
||||||
|
(let [text "@User Number One foo"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "@0xpk1 foo") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "starts with some text, then mention"
|
||||||
|
(let [text "text @User Number One"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "text @0xpk1") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "starts with some text, then mention, then more text"
|
||||||
|
(let [text "text @User Number One foo"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "text @0xpk1 foo") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "no space before mention"
|
||||||
|
(let [text "text@User Number One"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "text@0xpk1") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "two different mentions"
|
||||||
|
(let [text "@User Number One @User Number two"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "@0xpk1 @0xpk2") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "two different mentions inside text"
|
||||||
|
(let [text "foo@User Number One bar @User Number two baz"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "foo@0xpk1 bar @0xpk2 baz") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "ens mention"
|
||||||
|
(let [text "@user2"
|
||||||
|
result (mentions/replace-mentions text users)]
|
||||||
|
(test/is (= result "@0xpk2") (pr-str text))))
|
||||||
|
|
||||||
|
(test/testing "multiple mentions"
|
||||||
|
(let [text (string/join
|
||||||
|
" "
|
||||||
|
(repeat 1000 "@User Number One @User Number two"))
|
||||||
|
result (mentions/replace-mentions text users)
|
||||||
|
exprected-result (string/join
|
||||||
|
" "
|
||||||
|
(repeat 1000 "@0xpk1 @0xpk2"))]
|
||||||
|
(test/is (= exprected-result result))))))
|
|
@ -51,11 +51,14 @@
|
||||||
|
|
||||||
(defn get-all-contacts-in-group-chat
|
(defn get-all-contacts-in-group-chat
|
||||||
[members admins contacts {:keys [public-key] :as current-account}]
|
[members admins contacts {:keys [public-key] :as current-account}]
|
||||||
(let [current-contact (-> current-account
|
(let [current-contact (some->
|
||||||
|
current-account
|
||||||
(select-keys [:name :preferred-name :public-key :photo-path])
|
(select-keys [:name :preferred-name :public-key :photo-path])
|
||||||
(clojure.set/rename-keys {:name :alias
|
(clojure.set/rename-keys {:name :alias
|
||||||
:preferred-name :name}))
|
:preferred-name :name}))
|
||||||
all-contacts (assoc contacts public-key current-contact)]
|
all-contacts (cond-> contacts
|
||||||
|
current-contact
|
||||||
|
(assoc public-key current-contact))]
|
||||||
(->> members
|
(->> members
|
||||||
(map #(or (get all-contacts %)
|
(map #(or (get all-contacts %)
|
||||||
(public-key->new-contact %)))
|
(public-key->new-contact %)))
|
||||||
|
|
Loading…
Reference in New Issue