Skip to content

Commit

Permalink
[feature] add block user feature in user profile
Browse files Browse the repository at this point in the history
- add block/unblock action to user profile
- blocking deletes all messages from user and ignores future messages
- unblocking stops ignoring new messages from user but doesn't recover past ones
  • Loading branch information
yenda committed Jan 14, 2019
1 parent 86f0ab4 commit 7f5f0dd
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 31 deletions.
3 changes: 3 additions & 0 deletions resources/icons/cancel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/status_im/chat/models.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
:unviewed-messages-count 0
:deleted-at-clock-value last-message-clock-value})
:data-store/tx [(chats-store/clear-history-tx chat-id last-message-clock-value)
(messages-store/delete-messages-tx chat-id)]}))
(messages-store/delete-chat-messages-tx chat-id)]}))

(fx/defn deactivate-chat
[{:keys [db now] :as cofx} chat-id]
Expand Down
7 changes: 0 additions & 7 deletions src/status_im/chat/models/loading.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@
db
(group-by (comp time/day-relative :timestamp) messages))})

(fx/defn group-messages
[{:keys [db]}]
(reduce-kv (fn [fx chat-id {:keys [messages]}]
(group-chat-messages fx chat-id (vals messages)))
{:db db}
(:chats db)))

(defn- get-referenced-ids
"Takes map of `message-id->messages` and returns set of maps of
`{:response-to old-message-id :response-to-v2 message-id}`,
Expand Down
106 changes: 100 additions & 6 deletions src/status_im/contact/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@
[status-im.chat.models :as chat.models]
[status-im.contact.db :as contact.db]
[status-im.data-store.contacts :as contacts-store]
[status-im.data-store.messages :as data-store.messages]
[status-im.data-store.chats :as data-store.chats]
[status-im.i18n :as i18n]
[status-im.transport.message.contact :as message.contact]
[status-im.transport.message.protocol :as protocol]
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.fx :as fx]
[status-im.utils.utils :as utils]))
[status-im.utils.utils :as utils]
[status-im.chat.models.loading :as chat.models.loading]
[status-im.chat.models.message :as chat.models.message]))

(fx/defn load-contacts
[{:keys [db all-contacts]}]
(let [contacts-list (map #(vector (:public-key %) %) all-contacts)
contacts (into {} contacts-list)]
{:db (update db :contacts/contacts #(merge contacts %))}))
{:db (-> db
(update :contacts/contacts #(merge contacts %))
(assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts)))}))

(defn can-add-to-contacts? [{:keys [pending? dapp?]}]
(and (not dapp?)
Expand All @@ -26,11 +32,10 @@

(defn build-contact [{{:keys [chats] :account/keys [account]
:contacts/keys [contacts]} :db} public-key]
(cond-> (assoc (or (get contacts public-key)
(contact.db/public-key->new-contact public-key))
(cond-> (assoc (contact.db/public-key->contact contacts public-key)
:address (contact.db/public-key->address public-key))

(= public-key (:public-key account)) (assoc :name (:name account))))
(= public-key (:public-key account))
(assoc :name (:name account))))

(defn- own-info [db]
(let [{:keys [name photo-path address]} (:account/account db)
Expand Down Expand Up @@ -81,6 +86,95 @@
{:db (assoc-in db [:contacts/contacts public-key :tags] tags)
:data-store/tx [(contacts-store/remove-contact-tag-tx public-key tag)]}))

(fx/defn block-contact-confirmation
[cofx public-key]
{:utils/show-confirmation
{:title (i18n/label :t/block-contact)
:content (i18n/label :t/block-contact-details)
:confirm-button-text (i18n/label :t/to-block)
:on-accept #(re-frame/dispatch [:contact.ui/block-contact-confirmed public-key])}})

(defn get-removed-unseen-count
[current-public-key user-statuses removed-messages-ids]
(- (count removed-messages-ids)
(count (filter (fn [[_ statuses]]
(= :seen
(:status (get statuses
current-public-key))))
user-statuses))))

(fx/defn clean-up-chat
[{:keys [db get-stored-user-statuses] :as cofx} chat-id removed-chat-messages]
(let [current-public-key (accounts.db/current-public-key cofx)
removed-messages-ids (map :message-id removed-chat-messages)
user-statuses (get-stored-user-statuses chat-id
removed-messages-ids)
removed-unseen-count (get-removed-unseen-count current-public-key
user-statuses
removed-messages-ids)
db (-> db
;; remove messages
(update-in [:chats chat-id :messages]
#(apply dissoc % removed-messages-ids))
;; remove message statuses
(update-in [:chats chat-id :messages-statuses]
#(apply dissoc % removed-messages-ids))
;; remove message groups
(update-in [:chats chat-id]
dissoc :message-groups))]
(fx/merge cofx
{:db db}
;; update unviewed messages count
(chat.models/upsert-chat
{:chat-id chat-id
:unviewed-messages-count
(- (get-in db [:chats chat-id :unviewed-messages-count])
removed-unseen-count)})
;; recompute message group
(chat.models.loading/group-chat-messages
chat-id
(vals (get-in db [:chats chat-id :messages]))))))

(fx/defn clean-up-chats
[cofx removed-messages-by-chat]
(apply fx/merge cofx
(map (fn [[chat-id messages]]
(clean-up-chat chat-id messages))
removed-messages-by-chat)))

(fx/defn block-contact
[{:keys [db get-user-messages] :as cofx} public-key]
(let [contact (assoc (contact.db/public-key->contact
(:contacts/contacts db)
public-key)
:blocked? true)
user-messages (get-user-messages public-key)
user-messages-ids (map :message-id user-messages)
removed-messages-by-chat (group-by :chat-id user-messages)]
(fx/merge cofx
{:db (-> db
;; add the contact to blocked contacts
(update :contacts/blocked conj public-key)
;; update the contact in contacts list
(assoc-in [:contacts/contacts public-key] contact)
;; remove the 1-1 chat if it exists
(update-in [:chats] dissoc public-key))
:data-store/tx [(contacts-store/block-user-tx contact
user-messages-ids)]}
;;remove the messages from chat
(clean-up-chats removed-messages-by-chat)
(chat.models.message/update-last-messages
(keys removed-messages-by-chat)))))

(fx/defn unblock-contact
[{:keys [db]} public-key]
(let [contact (assoc (get-in db [:contacts/contacts public-key])
:blocked? false)]
{:db (-> db
(update :contacts/blocked disj public-key)
(assoc-in [:contacts/contacts public-key] contact))
:data-store/tx [(contacts-store/save-contact-tx contact)]}))

(defn handle-contact-update
[public-key
timestamp
Expand Down
10 changes: 10 additions & 0 deletions src/status_im/contact/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@
:photo-path (identicon/identicon public-key)
:public-key public-key})

(defn public-key->contact
[contacts public-key]
(when public-key
(get contacts public-key
(public-key->new-contact public-key))))

(defn public-key->address [public-key]
(let [length (count public-key)
normalized-key (case length
Expand Down Expand Up @@ -121,3 +127,7 @@
(map #(if (admins (:public-key %))
(assoc % :admin? true)
%)))))

(defn get-blocked-contacts
[contacts]
(into #{} (filter :blocked? contacts)))
13 changes: 11 additions & 2 deletions src/status_im/contact/subs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,17 @@
:<- [:contacts/contacts]
(fn [contacts]
(->> contacts
(remove (fn [[_ {:keys [pending? hide-contact?]}]]
(or pending? hide-contact?)))
(remove (fn [[_ {:keys [pending? hide-contact? blocked?]}]]
(or pending? hide-contact? blocked?)))
(contact.db/sort-contacts))))

(re-frame/reg-sub
:contacts/blocked
:<- [:contacts/contacts]
(fn [contacts]
(->> contacts
(filter (fn [[_ {:keys [blocked?]}]]
blocked?))
(contact.db/sort-contacts))))

(re-frame/reg-sub
Expand Down
33 changes: 31 additions & 2 deletions src/status_im/data_store/contacts.cljs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(ns status-im.data-store.contacts
(:require [goog.object :as object]
[re-frame.core :as re-frame]
[status-im.data-store.realm.core :as core]))
[status-im.data-store.realm.core :as core]
[clojure.set :as clojure.set]))

(defn- normalize-contact [contact]
(-> contact
Expand All @@ -21,7 +22,7 @@
(fn [realm]
(core/create realm
:contact
(dissoc contact :command :response :subscriptions)
contact
true)))

(defn save-contacts-tx
Expand All @@ -34,6 +35,34 @@
(defn- get-contact-by-id [public-key realm]
(core/single (core/get-by-field realm :contact :public-key public-key)))

(defn- get-messages-by-messages-ids
[message-ids]
(-> @core/account-realm
(.objects "message")
(.filtered (str "(" (core/in-query "message-id" message-ids) ")"))))

(defn- get-statuses-by-messages-ids
[message-ids]
(-> @core/account-realm
(.objects "user-status")
(.filtered (str "(" (core/in-query "message-id" message-ids) ")"))))

(defn block-user-tx
"Returns tx function for deleting user messages"
[{:keys [public-key] :as contact} messages-ids]
(fn [realm]
(core/create realm :contact contact true)
(let [chat (core/get-by-field realm :chat
:chat-id public-key)
user-messages (get-messages-by-messages-ids messages-ids)
user-messages-statuses (get-statuses-by-messages-ids messages-ids)
user-statuses (core/get-by-field realm :user-status :public-key public-key)]
(core/delete realm user-messages)
(core/delete realm user-messages-statuses)
(core/delete realm user-statuses)
(when chat
(core/delete realm chat)))))

(defn delete-contact-tx
"Returns tx function for deleting contact"
[public-key]
Expand Down
17 changes: 16 additions & 1 deletion src/status_im/data_store/messages.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,21 @@
(fn [cofx _]
(assoc cofx :get-referenced-messages get-references-by-ids)))

(defn get-user-messages
[public-key]
(.reduce (core/get-by-field @core/account-realm
:message :from public-key)
(fn [acc message-object _ _]
(conj acc
{:message-id (aget message-object "message-id")
:chat-id (aget message-object "chat-id")}))
[]))

(re-frame/reg-cofx
:data-store/get-user-messages
(fn [cofx _]
(assoc cofx :get-user-messages get-user-messages)))

(defn prepare-content [content]
(if (string? content)
content
Expand Down Expand Up @@ -112,7 +127,7 @@
(core/delete realm message)
(core/delete realm (core/get-by-field realm :user-status :message-id message-id)))))

(defn delete-messages-tx
(defn delete-chat-messages-tx
"Returns tx function for deleting messages with user statuses for given chat-id"
[chat-id]
(fn [realm]
Expand Down
18 changes: 18 additions & 0 deletions src/status_im/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
[status-im.signals.core :as signals]
[status-im.transport.message.core :as transport.message]
[status-im.ui.screens.currency-settings.models :as currency-settings.models]
[status-im.chat.models.message :as models.message]
[status-im.node.core :as node]
[status-im.web3.core :as web3]
[status-im.ui.screens.navigation :as navigation]
Expand Down Expand Up @@ -1317,6 +1318,23 @@
(fn [cofx [_ public-key]]
(contact/add-contact cofx public-key)))

(handlers/register-handler-fx
:contact.ui/block-contact-pressed
(fn [cofx [_ public-key]]
(contact/block-contact-confirmation cofx public-key)))

(handlers/register-handler-fx
:contact.ui/block-contact-confirmed
[(re-frame/inject-cofx :data-store/get-user-messages)
(re-frame/inject-cofx :data-store/get-user-statuses)]
(fn [cofx [_ public-key]]
(contact/block-contact cofx public-key)))

(handlers/register-handler-fx
:contact.ui/unblock-contact-pressed
(fn [cofx [_ public-key]]
(contact/unblock-contact cofx public-key)))

(handlers/register-handler-fx
:contact.ui/close-contact-pressed
(fn [cofx [_ public-key]]
Expand Down
7 changes: 5 additions & 2 deletions src/status_im/transport/message/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@

(fx/defn receive-message
[cofx now-in-s filter-chat-id js-message]
(let [{:keys [payload sig timestamp ttl]} (js->clj js-message :keywordize-keys true)
(let [blocked-contacts (get-in cofx [:db :contacts/blocked] #{})
{:keys [payload sig timestamp ttl]} (js->clj js-message :keywordize-keys true)
status-message (-> payload
transport.utils/to-utf8
transit/deserialize)]
(when (and sig status-message)
(when (and sig
status-message
(not (blocked-contacts sig)))
(try
(when-let [valid-message (protocol/validate status-message)]
(fx/merge (assoc cofx :js-obj js-message)
Expand Down
2 changes: 2 additions & 0 deletions src/status_im/ui/components/icons/vector_icons.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
:icons/flash-inactive (js/require "./resources/icons/flash_inactive.svg")
:icons/attach (js/require "./resources/icons/attach.svg")
:icons/browse (js/require "./resources/icons/browse.svg")
:icons/cancel (js/require "./resources/icons/cancel.svg")
:icons/close (js/require "./resources/icons/close.svg")
:icons/copy-from (js/require "./resources/icons/copy_from.svg")
:icons/delete (js/require "./resources/icons/delete.svg")
Expand Down Expand Up @@ -119,6 +120,7 @@
:icons/add-contact (components.svg/slurp-svg "./resources/icons/add_contact.svg")
:icons/add-wallet (components.svg/slurp-svg "./resources/icons/add_wallet.svg")
:icons/address (components.svg/slurp-svg "./resources/icons/address.svg")
:icons/cancel (components.svg/slurp-svg "./resources/icons/cancel.svg")
:icons/arrow-left (components.svg/slurp-svg "./resources/icons/arrow_left.svg")
:icons/angle-arrow-left (components.svg/slurp-svg "./resources/icons/angle_arrow_left.svg")
:icons/arrow-right (components.svg/slurp-svg "./resources/icons/arrow_right.svg")
Expand Down
13 changes: 11 additions & 2 deletions src/status_im/ui/screens/profile/contact/styles.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
:color colors/black}})

(def action-container
{:background-color colors/white
:padding-top 24})
{:background-color colors/white})

(def action
{:background-color (colors/alpha colors/blue 0.1)
Expand All @@ -47,6 +46,16 @@
(def action-icon-opts
{:color colors/blue})

(def block-action
{:background-color (colors/alpha colors/red 0.1)
:border-radius 50})

(def block-action-label
{:color colors/red})

(def block-action-icon-opts
{:color colors/red})

(def profile-setting-text-empty
(merge profile-setting-text
{:color colors/gray}))
Expand Down
Loading

0 comments on commit 7f5f0dd

Please sign in to comment.