[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.utils.datetime :as datetime]
|
||||
[status-im.utils.fx :as fx]
|
||||
["emojilib" :as emojis]))
|
||||
["emojilib" :as emojis]
|
||||
[status-im.chat.models.mentions :as mentions]))
|
||||
|
||||
(defn text->emoji
|
||||
"Replaces emojis in a specified `text`"
|
||||
|
@ -130,7 +131,8 @@
|
|||
(fx/defn send-current-message
|
||||
"Sends message from current chat input"
|
||||
[{{: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
|
||||
(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
|
||||
[members admins contacts {:keys [public-key] :as current-account}]
|
||||
(let [current-contact (-> current-account
|
||||
(select-keys [:name :preferred-name :public-key :photo-path])
|
||||
(clojure.set/rename-keys {:name :alias
|
||||
:preferred-name :name}))
|
||||
all-contacts (assoc contacts public-key current-contact)]
|
||||
(let [current-contact (some->
|
||||
current-account
|
||||
(select-keys [:name :preferred-name :public-key :photo-path])
|
||||
(clojure.set/rename-keys {:name :alias
|
||||
:preferred-name :name}))
|
||||
all-contacts (cond-> contacts
|
||||
current-contact
|
||||
(assoc public-key current-contact))]
|
||||
(->> members
|
||||
(map #(or (get all-contacts %)
|
||||
(public-key->new-contact %)))
|
||||
|
|
Loading…
Reference in New Issue